Building Python services through gRPC

Building Python services through gRPC

This presentations aims to show how to build services through gRPC in Python. It is presented 3 demos: A basic service covering all steps with Python+gRPC, a video streaming service and a TLS service. gRPC background, workflow, design and who is using are discussed as well.

B1412c9ed55333c1df561f64dfad69d3?s=128

Gustavo Pantuza

June 28, 2019
Tweet

Transcript

  1. Gustavo Pantuza

  2. Agenda • What is gRPC? • Background • Who is

    using • gRPC Workflow • Demo 0 • gRPC Design • Demo 1 • Security • Demo 2 • References
  3. What is gRPC? "A high performance, open-source universal RPC framework"

    Project site: https://grpc.io Github: https://github.com/grpc
  4. What is gRPC? • Remote Procedure Call • Type Safe

    • Polyglot • Binary message format • Multiplexed connections
  5. What is gRPC? A bunch of best practices gathered together

    to build a simple distributed systems tool My personal opinion
  6. What is gRPC?

  7. Background • General-purpose RPC infrastructure called Stubby Open Source

  8. Background Connect the large number of microservices running within and

    across our data centers
  9. Background Cloud Native Computing Foundation To Host gRPC from Google

  10. Who is using? "We’ve also seen a squishing and a

    narrowing of our latency windows" https://www.cncf.io/netflix-case-study/
  11. Who is using? "Implementing GRPC/Telemetry on XR devices" https://community.cisco.com/t5/service-providers-documents/implementing-grpc-telemetry-on-xr-devices/ta-p/3393966

  12. Who is using? "distribution layer is the first layer to

    communicate with other nodes" https://www.cockroachlabs.com/docs/stable/architecture/distribution-layer.html
  13. Who is using? "more compact and efficiently serializable RPC payload"

    https://cilium.io/blog/grpc/
  14. Who is using? "layers the best features of IDL-specified RPC

    onto a standard" https://linkerd.io/2017/01/11/http2-grpc-and-linkerd/#_ga=2.36853351.619173598.1561427300-69268088.1561427300
  15. Who is using? https://stackshare.io/grpc

  16. gRPC Workflow • The Message Protocol

  17. gRPC Workflow • The Message Protocol Message definition protoc Compiler

    Python Go C++
  18. syntax = "proto3"; package cheesefarm; Define the version and the

    package gRPC Workflow
  19. syntax = "proto3"; package cheesefarm; message Cheese { int32 age

    = 1; CheeseType type = 2; } enum CheeseType { EMMENTAL = 0; BRIE = 1; PECORINO = 2; ROQUEFORT = 3; CANASTRA = 4; } message CheeseRequest { CheeseType type = 1; } Create your messages gRPC Workflow
  20. syntax = "proto3"; package cheesefarm; message Cheese { int32 age

    = 1; CheeseType type = 2; } enum CheeseType { EMMENTAL = 0; BRIE = 1; PECORINO = 2; ROQUEFORT = 3; CANASTRA = 4; } message CheeseRequest { CheeseType type = 1; } service CheeseService { rpc Order(CheeseRequest) returns (Cheese); } Describe your Service interface gRPC Workflow
  21. $> # Install gRPC libraries $> pip install grpcio $>

    pip install grpcio-tools Install gRPC Python libraries gRPC Workflow
  22. $> # Compile gRPC files with Python $> # as

    target language in $> # the current directory $> python -m grpc_tools.protoc \ -I. \ --python_out=. \ --grpc_python_out=. \ cheese.proto Compilation time gRPC Workflow
  23. $> # Two new files generated: $> # 1. cheese_pb2.py

    $> Protocol Buffer message $> # 2. cheese_pb2_grpc.py $> gRPC Service Client/Server $> ls cheese_pb2* cheese_pb2.py cheese_pb2_grpc.py Compilation Results gRPC Workflow
  24. # Generated by the gRPC Python protocol compiler plugin. DO

    NOT EDIT! import grpc import cheese_pb2 as cheese__pb2 class CheeseServiceStub(object): # missing associated documentation comment in .proto file pass def __init__(self, channel): """Constructor. Args: channel: A grpc.Channel. """ self.Order = channel.unary_unary( '/cheesefarm.CheeseService/Order', request_serializer=cheese__pb2.CheeseRequest.SerializeToString, response_deserializer=cheese__pb2.Cheese.FromString, ) class CheeseServiceServicer(object): # missing associated documentation comment in .proto file pass def Order(self, request, context): # missing associated documentation comment in .proto file pass context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') Resulted code example gRPC Workflow
  25. import grpc from concurrent import futures from time import sleep

    from random import randint # Imports all Protoc generated classes/code import cheese_pb2 import cheese_pb2_grpc class CheeseService(cheese_pb2_grpc.CheeseServiceServicer): """ Extends the auto generated CheeseServiceServicer class from Protoc compiler. In this class we implement the service layer code """ def Order(self, request, context): """ Simulates a Cheese Order load and returns a Cheese """ # Implementation here def main(): # gRPC server server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) # Binds our service implementation to a gRPC server through the # auto generated function add_CheeseServiceServicer_to_server cheese_pb2_grpc.add_CheeseServiceServicer_to_server(CheeseService(), server) print('Listening on localhost:4000') server.add_insecure_port('localhost:4000') server.start() # server.start() will not block, so we run a sleep-loop to keep # alive server alive until an interruption try: while True: sleep(60 * 60) # Each hour the loop continues except KeyboardInterrupt: server.stop(0) Server Implementation gRPC Workflow
  26. from random import randint import grpc # Imports all Protoc

    generated classes/code import cheese_pb2 import cheese_pb2_grpc def main(): # gRPC channel channel = grpc.insecure_channel('localhost:4000') # create a stub (client) of our service stub = cheese_pb2_grpc.CheeseServiceStub(channel) while True: # Do cheeses orders cheese_request = cheese_pb2.CheeseRequest(type=randint(0, 4)) cheese = stub.Order(cheese_request) print("[gRPC] Received={0}".format( cheese_pb2.CheeseType.Name(cheese.type))) if __name__ == "__main__": main() Client Implementation gRPC Workflow
  27. Demo 0 The Cheese Service

  28. Demo 0

  29. gRPC Design Http/2 by design • Binary payload • Multiplexed

    connections • Extensible
  30. gRPC Design Streaming // From Server to Client rpc ListFeatures(Rectangle)

    returns (stream Feature) {} // From Client to Server rpc RecordRoute(stream Point) returns (RouteSummary) {} // Bidirectional rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} The classic pair Send() and Recv() from socket library
  31. gRPC Design Server streaming // From Server to Client rpc

    Watch(Match) returns (stream Video) {}
  32. gRPC Design Client streaming // From client to Client rpc

    Upload(stream chunks) returns (Done) {}
  33. Demo 1 The Soccer Match Service

  34. syntax = "proto3"; package stream; message Match { string id

    = 1; } message Video { bytes data = 1; string data_type = 2; string data_shape = 3; } service Soccer { rpc Watch (Match) returns (stream Video) {} } Protocol Buffer Demo 1
  35. class SoccerService(stream_pb2_grpc.SoccerServicer): """ Soccer Matches stream service based on gRPC

    """ def Watch(self, request, context): """ Returns a stream to a Match stream """ print("[gRPC] Match={0}".format(request.id)) file_path = "{0}.mp4".format(request.id) match = cv2.VideoCapture(file_path) while match.isOpened(): ret_val, frame = match.read() if not ret_val: break video = stream_pb2.Video( data=frame.tobytes(), data_type=frame.dtype.name, data_shape=str(frame.shape), ) yield video match.release() Server Implementation Demo 1
  36. def main(): channel = grpc.insecure_channel('localhost:4000') stub = stream_pb2_grpc.SoccerStub(channel) match =

    stream_pb2.Match(id="KKNuUdn4wI4") iterator = stub.Watch(match) try: for video in iterator: frame = np.frombuffer( video.data, dtype=video.data_type ).reshape(literal_eval(video.data_shape)) cv2.imshow(match.id, frame) if cv2.waitKey(1) == 27: break # esc to quit cv2.destroyAllWindows() except grpc._channel._Rendezvous as err: print(err) sleep(3) Client Implementation Demo 1
  37. Demo 1 The Soccer Match Service

  38. gRPC Design Bidirectional streaming // Bidirectional rpc Chat(stream video) returns

    (stream video) {}
  39. gRPC Design Blocking & Non-Blocking

  40. gRPC Design Cancellation & Timeout

  41. gRPC Design Pluggable Large distributed systems need: • Security •

    Health-checking • Load-balancing • Failover • Monitoring • Tracing • logging Python Interceptor example
  42. gRPC Design Standardized Status Codes CODE NUMBER OK 0 CANCELLED

    1 UNKNOWN 2 INVALID_ARGUMENT 3 ... ... https://github.com/grpc/grpc/blob/master/doc/statuscodes.md
  43. gRPC security Supported and Authentication methods https://grpc.io/docs/guides/auth/

  44. gRPC security TLS On the Server # gRPC server server

    = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) cheese_pb2_grpc.add_CheeseServiceServicer_to_server(CheeseService(), server) # Load SSL files ssl_key = open("ssl/private.key", "rb").read() ssl_cert = open("ssl/cert.pem", "rb").read() credentials = grpc.ssl_server_credentials([(ssl_key, ssl_cert)]) print('Listening on localhost:4000') server.add_secure_port('localhost:4000', credentials) server.start()
  45. gRPC security TLS On the Client # Load Certificate file

    trusted_cert = open("ssl/cert.pem", "rb").read() credentials = grpc.ssl_channel_credentials(root_certificates=trusted_cert) # gRPC channel channel = grpc.secure_channel('localhost:4000', credentials) # create a stub (client) of our service stub = cheese_pb2_grpc.CheeseServiceStub(channel)
  46. Demo 2 The Cheese SECURE Service

  47. gRPC References • Official project site • Official project Repositories

    • Awesome gRPC project • Official examples for other languages • Protocol Buffer official site
  48. gRPC Python Examples • A simplified guide to gRPC in

    Python • gRPC Basics - Python • Python Quick Start • Python gRPC official example • Tutorial – Writing your first gRPC service in Python
  49. Hey developers, please, play with me <3