This is the 12th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

1 meaning

The REMOTE Procedure Call (RPC) framework actually provides a mechanism for applications to communicate with each other, and also complies with the Server/Client model. When used, the client calls the interface provided by the server as if it were calling a local function.

GRPC is a high-performance, open source, and generic RPC framework designed for mobile and HTTP/2. Currently, C, Java, and Go languages are available: GRPC, GRpc-Java, and GRPC-Go. The C version supports C, C++, Node.js, Python, Ruby, Objective-C, PHP, and C#.

GRPC is designed based on the HTTP/2 standard and brings features such as bidirectional streaming, flow control, header compression, and multiplex requests over a single TCP connection. These features allow it to perform better on mobile devices, saving power and space. The following figure shows a typical gRPC structure.

2 Defining services

GRPC is based on the idea of defining a service and specifying methods that can be called remotely, along with their parameters and return types. GRPC defaults to using Protocol Buffers as the interface definition language to describe the service interface and payload message structure. Other alternatives can be used if necessary.

service HelloService {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  required string greeting = 1;
}

message HelloResponse {
  required string reply = 1;
}
Copy the code

2.1 Four ways to define services

2.1.1 single RPC

  • The client sends a request to the server and gets a response from the server, just like a normal function call.
rpc SayHello(HelloRequest) returns (HelloResponse){
}
Copy the code

2.1.2 Streaming RPC on the server

  • The client sends a request to the server to get a data stream to read a series of messages. The client reads from the returned data stream until there are no more messages.
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){
}
Copy the code

2.1.3 Client Streaming RPC

  • The client writes and sends a series of messages to the server using one of the data streams provided. Once the client has finished writing the messages, it waits for the server to read them and return a reply.
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {
}
Copy the code

2.1.4 Two-way streaming RPC

  • Each side can send a series of messages via a read/write data stream. The two data flow operations are independent of each other, so the client and server can read and write in any order they wish. For example, the server can wait for all client messages before writing a reply, or it can read one message and then write another, or some other combination of read and write. The order of messages in each data stream is maintained.
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){
}
Copy the code

2.1.5 Using API Interfaces

GRPC provides a Protocol Buffer compiler plug-in that can generate client and server code from a service defined.proto file. Typically gRPC users can implement these apis on the server side and invoke them from the client side.

  • On the service side, the server implements the service interface and runs a gRPC server to handle client calls. The gRPC infrastructure decodes incoming requests, executes service methods, and encodes service responses.
  • On the client side, the client side has oneThe stubImplements the same method on the server side. The client can call these methods on a local stub, encapsulating the parameters with the appropriate Protocol Buffer message type – gRPC – to take care of sending the request to the server and returning the server’s Protocol Buffer response.

2.1.6 Synchronous vs. Asynchronous

Synchronous RPC calls block until a reply is received from the server, which is the closest abstraction RPC wants. On the other hand, the network is asynchronous internally, and the ability to start RPC without blocking the current thread can be very useful in many scenarios.

In most languages, the gRPC programming interface supports both synchronous and asynchronous features. You can find more from each language tutorial and reference documentation (full documentation will be available soon).

2.2 RPC Life Cycle

Now let’s take a closer look at what happens when a gRPC client calls a gRPC server method. We won’t go into implementation details, but you can find more details on implementation details on our language-specific page.

2.2.1 single RPC

First, let’s look at the simplest form of RPC: the client makes a single request and gets a single response.

  • Once a client invokes a method through a peg, the server is notified of the client’s metadata, the method name, and the allowed response time (if available).
  • Depending on the application, the server can either send back the original metadata directly before any response or wait for the client to request information.
  • Once the server has the client’s request information, it does whatever it needs to do to create or assemble the corresponding response. If successful, the response is returned to the client with the status details and optional trace information including the status code and optional status information.
  • If the status is OK, the client gets an answer, which terminates the client call.

2.2.2 Streaming RPC on the server

Server-side streaming RPC is the same as in our simple example, except that it sends back a reply stream upon receiving the client request information. After all replies are sent, the server’s status details (status codes and optional status information) and optional trace metadata are sent back to the client to complete the server’s work. The client also completes its work after receiving all the replies from the server.

2.2.3 Client streaming RPC

Client-side streaming RPC is basically the same as our simple example, except that the client sends a request stream to the server instead of sending a single request. The server usually (but not necessarily) sends back a reply with details of its status and optional trace data after receiving all requests from the client.

2.2.4 Two-way streaming RPC

Two-way streaming RPC, where the call is initialized by the client calling the method, and the server receives the client’s metadata, method name, and expiration date. The server can choose to send back its initial metadata or wait for the client to send the request. What happens next depends on the application, because clients and servers can read and write in any order – the operations of these streams are completely independent. For example, the server can wait until it receives all the messages from the client before writing a reply, or the server and client can act like “ping-pong balls” : the server receives a request and sends a reply, the client sends another request based on the reply, and so on.

2.2.5 Deadline

GRPC allows clients to specify a deadline value before calling a remote method. This value specifies how long the client can wait for the server to reply, after which the RPC will end with a DEADLINE_EXCEEDED error. The expiration value can be queried on the server side to see if a particular method has expired or how much time is left to complete the method. The way languages specify a cutoff time varies – a cutoff value is always required in Python, for example, but not all languages have a default cutoff time.

2.2.6 RPC termination

In gRPC, client and server judgments of call success are independent and local, and their conclusions may differ. This means that, for example, if you have an RPC that terminates successfully on the server (” I have returned all replies! ), by which time the client may have failed (” Reply came after deadline!” ). It is also possible that the server decides that the call is complete before the client has finished sending all the requests.

Cancel the RPC 2.2.7

Either client or server can cancel an RPC at any time. A cancellation immediately terminates the RPC so that no more operations can be performed. It is not an “undo” and will not be rolled back if it has been done before cancellation. Of course, RPC calls made through synchronization cannot be cancelled because control of the program has not been returned to the application until the RPC ends.

2.2.8 Metadata set

Metadata is the information associated with a particular RPC call in the form of key-value pairs, typically of type string for keys and type string for values (which can also be binary data). Metadata is opaque to gRPC’s capabilities – it allows clients to provide information about calls to servers and vice versa. Access to metadata is language dependent.

2.2.9 channel

When client stubs are created, a gRPC channel provides a connection to a particular host and port server. The client can modify the default behavior of gRPC by specifying channel parameters, such as turning message compression on or off. A channel has state, both connected and idle. How gRPC handles closed channels is language dependent. Some languages allow you to ask for channel status.

3 Advantages of gRPC:

  • GRPC can define interfaces through protobuf, which can have stricter interface constraints. For protobuf, see my short Google Protobuf tutorial
  • In addition, with Protobuf, data can be serialized to binary encoding, which greatly reduces the amount of data that needs to be transferred, thus greatly improving performance.
  • GRPC can easily support streaming communication (theoretically it is possible to use the streaming mode through HTTP2.0, but generally the restful apis of Web services seem to be rarely used in this way. Usually streaming data applications such as video streaming usually use specialized protocols such as HLS, RTMP, etc. These are not our usual Web services, but dedicated server applications.)

4 Application Scenarios

  • To the interface need to be strict constraints, we provides a public service, for example, many people, even people outside of the company can also access the service, then we hope to have more strict constraint for interface, we don’t want the client to send us any data, especially considering the safety factor, We often need to impose tighter constraints on interfaces. GRPC can then provide strict interface constraints via protobuf.
  • For higher performance requirements. GRPC services can also be used when a service needs to transfer a large amount of data without affecting performance, because with Protobuf we can compress and encode the data into binary format, usually with a much smaller amount of data, and with HTTP2 we can implement asynchronous requests. Thus, the communication efficiency is greatly improved.

However, gRPC is usually used as a component rather than as a standalone component, because in production environments, we need to use distributed systems to handle large concurrency situations, and gRPC does not provide the necessary components for distributed systems. Moreover, true online services need to provide the necessary components including load balancing, current limiting circuit breakers, monitoring alarms, service registration and discovery, and so on. However, that is not the subject of this article, so let’s continue to look at how to use gRPC.

5 Getting Started

This time try python code to implement Hello World introductory case. The use of gRPC usually involves the following steps:

  1. Define interfaces and data types using protobuf
  2. Write gRPC server code
  3. Write gRPC client code

The catalogue of the whole project is as follows:

5.1 Configuring the gRPC Environment

Operating system different configuration environment of the way is also different, I try the Win10 environment. First explain how to configure the method in the Win10 environment.

5.1.1 installation Protobuf

Run in Ubuntu:

pip install protobuf    Install the Protobuf library
sudo apt-get install protobuf-compiler  Install the Protobuf compiler
Copy the code

Win10 under:

Login official website: address, select win64 – bit version.

Then in the environment variable, unzip the downloaded file and write the directory to the environment variable. I in C: \ protoc 3.17.3 – win64 \ bin.

Then execute: protoc –version in CMD.

At this point the environment configuration is complete, and then execute:

pip install protobuf    Install the Protobuf library
Copy the code

Install the Python library for Protobuf.

5.1.2 Installing the GPRC Tools Library

pip install grpcio-tools
Copy the code

5.1.3 Defining interfaces

Define interfaces and data types using Protobuf. Create a new protos folder, go inside and create a new HelloWorld.proto file and add the following:

syntax = "proto3";
package rpc_package;
// define a service
service HelloWorldService {
    // define the interface and data type
    rpc SayHello (HelloRequest) returns (HelloReply) {}}// define the data type of request
message HelloRequest {
    string name = 1;
}
// define the data type of response
message HelloReply {
    string message = 1;
}
Copy the code

Create a new rpc_package folder and use the gRPC Protobuf builder to generate library functions for the appropriate language. The generated directory is specified to the rpc_package folder.

python -m grpc_tools.protoc -I=./protos --python_out=./rpc_package --grpc_python_out=./rpc_package ./protos/helloworld.proto
Copy the code

Generate two files: helloWorld_pb2. py and helloWorld_PB2_grpc. py.

Create a _init_.py file under rpc_package and modify helloWorld_PB2_grpc. py () :

import rpc_package.helloworld_pb2 as helloworld__pb2
Copy the code

Otherwise, there will be a problem of not finding the library.

5.2 Server Code and Client Code

hello_server.py

#! /usr/bin/env python
# -*-coding: utf-8 -*-

from concurrent import futures
import grpc
import logging
import time
from rpc_package.helloworld_pb2_grpc import add_HelloWorldServiceServicer_to_server,HelloWorldServiceServicer
from rpc_package.helloworld_pb2 import HelloRequest, HelloReply


class Hello(HelloWorldServiceServicer) :

    This implements the interface we defined
    def SayHello(self, request, context) :
        return HelloReply(message='Hello, %s! ' % request.name)


def serve() :
    Thread pool is used to concurrently process server tasks
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))

    Add the corresponding task handling function to the RPC Server
    add_HelloWorldServiceServicer_to_server(Hello(), server)

    # The non-secure interface used here, the world gRPC supports TLS/SSL secure connections, as well as various authentication mechanisms
    server.add_insecure_port('[: :] : 50000')
    server.start()
    try:
        while True:
            time.sleep(60 * 60 * 24)
    except KeyboardInterrupt:
        server.stop(0)


if __name__ == "__main__":
    logging.basicConfig()
    serve()
Copy the code

hello_client.py

#! /usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import print_function
import logging

import grpc
from rpc_package.helloworld_pb2 import HelloRequest, HelloReply
from rpc_package.helloworld_pb2_grpc import HelloWorldServiceStub

def run() :
    # use the with syntax to ensure that the channel is closed automatically
    with grpc.insecure_channel('localhost:50000') as channel:
        The client implements RPC communication via stubs
        stub = HelloWorldServiceStub(channel)
        The client must use a defined type, in this case the HelloRequest type
        response = stub.SayHello(HelloRequest(name='AI hao'))
    print ("hello client received: " + response.message)

if __name__ == "__main__":
    logging.basicConfig()
    run()
Copy the code

5.3 run

Start by executing the server-side code

python hello_server.py
Copy the code

Then execute the client

python hello_client.py
Copy the code

Running results:

Hello client received: Hello, AI Ho!Copy the code

Reference article:

GRPC Details – Jianshu.com