\

♚ \

Author: xnow. Me

Blog: zhihu.com/people/xnow.me

Personally, gRPC has been in and out of fashion, it seems that no one around the use of gRPC, but every once in a while I hear some gRPC news, today happened to be a team to support gRPC, so I also test how to use Python to write gRPC service. RPC is the abbreviation of Remote Procedure Call, which can be understood as RPC is to Call Remote functions as local functions. GRPC is the Open source RPC framework of Google.

Here is a simple Example of a Python gRPC calculator that can add and multiply:

Version Information:

Python 3.68.
grpcio 1.25. 0
grpcio-tools 1.25. 0
nginx version: nginx/1.14. 0
Copy the code

Start Environment Preparation

Grpcio-tools uses Protobuf code generator for gRPC to generate Python code according to our protocol buffer definition. Protocolbuffers/Protobuf is a Protocol developed by Google to serialize data structures. Specific structure and grammar, now is not much to do too much understanding, as long as the use of the line.

$ sudo pip3 install grpcio grpcio-tools
Copy the code

Define services: Use the protocolBuffers /protobuf format to create a structured data file simplecal.proto, which reads as follows:

syntax = "proto3";

service Cal {
  rpc Add(AddRequest) returns (ResultReply) {}
  rpc Multiply(MultiplyRequest) returns (ResultReply) {}
}

message AddRequest {
  int32 number1  = 1;
  int32 number2  = 2;
}

message MultiplyRequest {
  int32 number1  = 1;
  int32 number2  = 2;
}

message ResultReply {
  int32 number = 1;
}
Copy the code

A service Cal is defined in the simplecal.proto file with two RPC methods, Add and Multiply, which need to be added and multiplied on the server side of the gRPC, respectively.

At the same time, we also define the parameters of two methods. The parameter of Add method is AddRequest, which contains two integer parameters number1 and number2. The Multiply method takes the MultiplyRequest parameter and also contains two integer parameters, number1 and number2. The return structure of both functions is ResultReply, and the content is an integer.

Generate Python code based on the above definition:

$ python3 -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./SimpleCal.proto
$ ls
SimpleCal_pb2_grpc.py  SimpleCal_pb2.py  SimpleCal.proto
Copy the code

Use python3 -m grpc_tools.protoc –hel to obtain the meaning of the command parameters. Grpc_tools: simplecal_pb2_grpc. py: simplecal_pb2.py These two files will be referenced later in the client and server code.

Examples of server and client

Here is the server code cal_server.py:

from concurrent import futures
import grpc
import SimpleCal_pb2
importSimpleCal_pb2_grpc class CalServicer(simplecal_pb2_grpc.calservicer): def Add(self, request, context): # Addprint("Add function called")
    returnSimpleCal_pb2.ResultReply(number=request.number1 + request.number2) def Multiply(self, request, context): The implementation logic of the # Multiply functionprint("Multiply service called")
    return SimpleCal_pb2.ResultReply(number=request.number1 * request.number2)

def serve():
  server = grpc.server(futures.ThreadPoolExecutor(max_workers=5))
  SimpleCal_pb2_grpc.add_CalServicer_to_server(CalServicer(),server)
  server.add_insecure_port("[...] : 50051")
  server.start()
  print("grpc server start...")
  server.wait_for_termination()

if __name__ == '__main__':
  serve()
Copy the code

The focus here is on the implementation of the Add and Multiply methods in the CalServicer class. The logic is simple: get number1 and number2 from the request and add them up. Note that all variables here need full names: Request.number1 and Request.number2, and positional arguments cannot be used. The implementation of Multiply is the same as Add, without further ado. The serve function defines the running mode of gRPC, using the thread pool of 5 workers.

Client code cal_client.py:

import SimpleCal_pb2
import SimpleCal_pb2_grpc
import grpc

def run(n, m):
  channel = grpc.insecure_channel('localhost:50051'Stub = simplecal_pb2_grpc. CalStub(channel) Response = stub.add (simplecal_pb2. AddRequest(number1=n, Number2 =m)) # execute the calculation commandprint(f"{n} + {m} = {response.number}")
  response = stub.Multiply(SimpleCal_pb2.MultiplyRequest(number1=n, number2=m))
  print(f"{n} * {m} = {response.number}")

if __name__ == "__main__":
  run(100.300)
Copy the code

The logic on the client side is simpler, just connect to the gRPC service and initiate the call. Start the server and execute the client code to call the gRPC service as follows:

$ python3 cal_server.py  &
$ python3 cal_client.py 
100 + 300 = 400
100 * 300 = 30000
Copy the code

The result indicates that both the client and server are running properly. For more examples of gRPC, visit the Example of gRPC/gRPC website.

https://github.com/grpc/grpc/tree/master/examples/python
Copy the code

Use Nginx to proxy gRPC

GRPC is based on the HTTP/2 protocol. Nginx started supporting HTTP/2 in 1.9.5 and gRPC in 1.13.10. –with-http_ssl_module –with-http_v2_module –with-http_v2_module –with-http_ssl_module

Add the following server configuration to Nginx:

server {
    listen 80 http2;

    location / {
      grpc_pass grpc://localhost:50051;}}Copy the code

Add the server configuration to the HTTP section of Nginx. After configuring and starting Nginx, Py with channel = grpc.insecure_channel(‘localhost:50051’). The result is the same, so I’m not going to do it again.

To dig into gRPC’s HTTP2.0 interface details, open simplecal_pb2_grpc. py and you can see that in the __init__ method of the CalStub class, the Add and Multiply functions are defined as urIs.

class CalStub(object):
  # missing associated documentation comment in .proto file
  pass

  def __init__(self, channel):
    """Constructor. Args: channel: A grpc.Channel. """
    self.Add = channel.unary_unary(
        '/Cal/Add'#, this is corresponding to the Add method of HTTP url request_serializer = SimpleCal__pb2. AddRequest. SerializeToString, response_deserializer=SimpleCal__pb2.ResultReply.FromString, ) self.Multiply = channel.unary_unary('/Cal/Multiply'#, this is the address of the HTTP url corresponding to Multiply method request_serializer = SimpleCal__pb2. MultiplyRequest. SerializeToString, response_deserializer=SimpleCal__pb2.ResultReply.FromString, )Copy the code

A look at the Nginx log shows this as well:

127.0. 01.- -18/Nov/2019:20:09:25 +0800"POST/Cal/Add HTTP / 2.0" 200 8 "-" "GRPC - the python / 1.25.0 GRPC - c / 8.0.0 (manylinux; chttp2; game)"
127.0. 01.- -18/Nov/2019:20:09:25 +0800"POST/HTTP / 2.0 Cal/Multiply" 200 9 "-" "GRPC - the python / 1.25.0 GRPC - c / 8.0.0 (manylinux; chttp2; game)"
Copy the code

If multiple gRPC servers are deployed, you can also use Nginx’s upstream to load balance multiple backend servers.

Finally, Wireshark is used to capture http2 traffic.

Capture HTTP2 data packets for gRPC protocol analysis

Reference article:

Introducing gRPC Support with NGINX 1.13.10 – NGINX

https://www.nginx.com/blog/nginx-1-13-10-grpc/
Copy the code

GRPC Official Document Chinese version _v1.0

https://doc.oschina.net/grpc?t=60138
Copy the code

grpc/grpc

https://github.com/grpc/grpc/tree/master/examples/python
Copy the code

Click become:Community registered members ** like the article, click the **Looking at the