Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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.

Gustavo Pantuza

June 28, 2019
Tweet

More Decks by Gustavo Pantuza

Other Decks in Programming

Transcript

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

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

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

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

    to build a simple distributed systems tool My personal opinion
  5. Who is using? "We’ve also seen a squishing and a

    narrowing of our latency windows" https://www.cncf.io/netflix-case-study/
  6. Who is using? "distribution layer is the first layer to

    communicate with other nodes" https://www.cockroachlabs.com/docs/stable/architecture/distribution-layer.html
  7. 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
  8. 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
  9. 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
  10. $> # Install gRPC libraries $> pip install grpcio $>

    pip install grpcio-tools Install gRPC Python libraries gRPC Workflow
  11. $> # 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
  12. $> # 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
  13. # 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
  14. 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
  15. 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
  16. 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
  17. gRPC Design Server streaming // From Server to Client rpc

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

    Upload(stream chunks) returns (Done) {}
  19. 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
  20. 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
  21. 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
  22. gRPC Design Pluggable Large distributed systems need: • Security •

    Health-checking • Load-balancing • Failover • Monitoring • Tracing • logging Python Interceptor example
  23. 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
  24. 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()
  25. 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)
  26. gRPC References • Official project site • Official project Repositories

    • Awesome gRPC project • Official examples for other languages • Protocol Buffer official site
  27. 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