Microservice Development Manual GRPC

GRPC is a high-performance, universal open source RPC framework developed based on the HTTP/2 protocol standard and Protobuf serialization protocol, and supports many development languages.

Article directory

  • 1 Introduction
    • 1.1 http2
      • 1.1.1 Binary transmission
      • 1.1.2 Header compression
      • 1.1.3 Multiplexing
      • 1.1.4 Server push
    • 1.2 Protobuf
      • 1.2.1 Advantages
      • 1.2.2 Disadvantages
      • 1.2.3 Comparison with other serialization methods
  • 2 grpc four modes
  • 3 Integrate springcloud
    • 3.1 Implement public protobuf and call it remotely through java grpc
        • Advantages and Disadvantages Analysis
    • 3.2 Use protobuf to define the interface each time (integrate net.devh.grpc)
  • 4 Service discovery and load balancing
    • 4.1 Dubbo
    • 4.2 springcloud
    • 4.3 istio
  • 5 grpc interceptor
    • 5.1 server interceptor
    • 5.2 client interceptor
  • 6 grpc monitoring full link
  • 7 grpc monitoring prometheus
  • 8grpc circuit breaker
  • 9 grpc high concurrency optimization warm-up
  • 10 grpc error reports and solutions

1 Introduction

In the GRPC framework, the client can directly call server-side methods located on different machines just like calling local objects, so that we can easily create some distributed application services.

On the server side, we implement the defined services and methods that can be called remotely, and run a gRPC server to handle client requests; on the client side, gRPC implements a stub (can be simply understood as a client), which provides Same method on the server side.

gRPC uses protocol buffers as the interface description language (IDL) and underlying information exchange format. It is generally recommended to use proto3 because it can support more languages and reduce some compatibility issues.
Since gRPC involves several important technical points, http2 and protobuf, it is these technical points that make gRPC widely used. Here we will also talk about these technical points.

1.1 http2

HTTP/2 is the latest HTTP protocol, which improves resource access efficiency. Through this popular science article, you can understand the concepts and advantages of the HTTP/2 protocol.

HTTP/2 is also called HTTP 2.0. Compared with HTTP 1.1, it has new features such as multiplexing, compressing HTTP headers, request prioritization, and server push. It solves the problems that have always existed in HTTP 1.1 and optimizes requests. performance while being compatible with the semantics of HTTP 1.1.

In 2015, HTTP/2 was released. HTTP/2 is a replacement for the current HTTP protocol (HTTP/1.1), but it is not a rewrite. HTTP methods, status codes, and semantics are the same as HTTP/1.1. Compared with HTTP/1.1, HTTP/2 can be said to have greatly improved the performance of web pages. Just upgrading to this protocol can reduce a lot of performance optimization work that needed to be done before. HTTP/2 is based on SPDY and focuses on performance. The biggest goal is to use only one connection between the user and the website.

HTTP/2 new features

1.1.1 Binary transmission

There are two main reasons for the significant reduction in the amount of data transmitted by HTTP/2: binary transmission and header compression. Let’s first introduce binary transmission. HTTP/2 uses binary format to transmit data instead of plain text messages in HTTP/1.1. The binary protocol is more efficient to parse. HTTP/2 splits request and response data into smaller frames, and they are binary encoded. At the heart of all performance enhancements in HTTP/2 is the new binary framing layer, which defines how HTTP messages are encapsulated and transmitted between the client and server.

1.1.2 Header compression

The header of HTTP/1.1 contains a large amount of information and must be sent repeatedly every time. HTTP/2 does not use the traditional compression algorithm. Instead, it develops a special “HPACK” algorithm to establish a “dictionary” on both ends of the client and server. “, using index numbers to represent repeated strings, and also using Huffman coding to compress integers and strings, which can achieve a high compression rate of 50% to 90%.

1.1.3 Multiplexing

Multiplexing allows multiple request-response messages to be initiated through a single HTTP/2 connection at the same time, which effectively solves the problem of browsers limiting the number of requests under the same domain name, and makes it easier to achieve full-speed transmission.

1.1.4 Server Push

HTTP2 has also changed the traditional “request-response” working model to a certain extent. The server is no longer completely passive in responding to requests, but can also create a new “stream” to actively send messages to the client. For example, when the browser just requests HTML, it sends the JS and CSS files that may be used to the client in advance to reduce the waiting delay. This is called “Server Push” (also called Cache push).

1.2 Protobuf

Protocol buffers are a language-neutral, platform-independent, extensible serialized data format that can be used for communication protocols, data storage, etc.

Protocol buffers are flexible and efficient when it comes to serializing data. Compared to XML, Protocol buffers are smaller, faster, and simpler. Once the data structure of the data to be processed is defined, the code generation tool of Protocol buffers can be used to generate the relevant code. Data structures can even be updated without redeploying the program. Use Protobuf to describe your data structure once, and your structured data can be easily read and written in a variety of different languages or from a variety of different data streams.

Protocol buffers are well suited for data storage or RPC data exchange formats. A language-independent, platform-independent, and extensible serialized structured data format that can be used in communication protocols, data storage and other fields.

1.2.1 Advantages

1. Good performance/high efficiency

Time cost: The cost of XML formatting (serialization) is okay; but the cost of XML parsing (deserialization) is not complimentary. But protobuf has been optimized in this aspect. It can reduce the time overhead of serialization and deserialization.

Space overhead: also reduced a lot

2. There is a code generation mechanism

For example, you can write something similar to a structure.

 message testA
{
    required int32 m_testA = 1;
}

Like writing such a structure, protobuf can automatically generate its .h file and .cpp file.
protobuf encapsulates the operation of structure testA into a class.

3. Support backward compatibility and forward compatibility

When the client and server use the same protocol, when the client adds a byte to the protocol, it will not affect the client’s use.

4. Support multiple programming languages

The source code officially released by Google contains three languages: c++, java, and Python.

1.2.2 Disadvantages

1. Binary format leads to poor readability

In order to improve performance, protobuf uses binary format for encoding. This directly leads to poor readability. This directly affects the efficiency during development and testing. Of course, under normal circumstances, protobuf is very reliable and does not cause major problems.

2. Lack of self-description

Generally speaking, XML is self-describing, while protobuf format is not. Give you a piece of protocol content in binary format. If it doesn’t match the structure you wrote, you won’t be able to see its effect.

3. Poor versatility

Although protobuf supports serialization and deserialization in a large number of languages, it is still not a cross-platform and language transmission standard. In multi-platform messaging, the compatibility with other projects is not very good, and corresponding adaptation and transformation work needs to be done. Compared with json and XML, the versatility is still not that good.

1.2.3 Comparison with other serialization methods

protobuf processes integers very quickly. If you need to understand the principle, you can check out the efficient data compression encoding method Protobuf

For comparison with other serialization methods and usage scenarios, please refer to the following article
Is Protobuf 5 times faster than JSON? Use code to break the pb performance myth

Comprehensive evaluation: Is Protobuf performance 5 times faster than JSON?

2 grpc four modes

1. Simple mode: Simple mode just uses parameters and return values as the way to transfer data between the server and the client, which is the simplest.

2. Client stream mode: That is, the stream is used to send data from the client to the server, that is, the server-side parameters are stream types, but after the server responds, the data is returned to the client, and the stream send method is also used. Generally, code on the server side needs to recv first and then send, while the client side is the opposite. But you can use go’s coroutine collaboration in the later two-way mode.

3. Server-side streaming mode: That is, the server-side uses the streaming mode when returning results, that is, the incoming data is passed in in the form of parameters. However, using the send method when sending data to the client is similar to the way the client returns data.

4. Bidirectional mode: If the client does not use coroutines, sending must occur before receiving. If you use coroutines, there is no order of sending and receiving. In order to ensure the synchronization of coroutines, mutexes can be used for constraints.

If you want to learn more about the detailed demo, you can view the Chinese version of gRPC official documentation.

3 Integrate springcloud

There are two options for integrating grpc here:

3.1 Implement public protobuf and call it remotely through java grpc

This solution eliminates the need to write protobuf. You can directly provide java api like dubbo to implement rpc calls. For details, please refer to the demo on github.
ttps://github.com/ChinaSilence/spring-boot-starter-grpc

  • facade: An independent Maven module that depends on spring-boot-starter-grpc. Methods that need to be called remotely are defined in this module. The form can be interface or abstract class

  • server: Service provider, relying on the facade module, needs to implement the interface defined by the facade module or the abstract method of the abstract class

  • client: The service caller depends on the facade module. When using it, just call it directly.

Analysis of advantages and disadvantages

advantage:

  • No need to write probuff files, define the interface in the form of java api

  • Does not depend on eureka, perfectly suitable for k8s

shortcoming:

  • Only supports Java. If you want to support heterogeneous languages, you need to use springcloudsidecar or manually register to eureka.
  • Eureka has limited support and does not support load balancing

3.2 Use protobuf to define the interface each time (integrate net.devh.grpc)

There is a lot more content here, please refer to my blog for details.
Springcloud integrates grpc (1)
Integration in this way requires writing proto interface files and automatically generating code every time, and both the client and server need to assemble additional parameters.

However, the advantage is that it has detailed interface specifications (protobuf) and can support heterogeneous language calls.

Later, we will introduce the integration method that only uses Java language, but does not need to write proto files every time.

4 Service discovery and load balancing

The gRPC open source component officially does not directly provide the function implementation of service registration and discovery, but its design document has provided implementation ideas, and has provided name resolution and load balancing interfaces for expansion in the gRPC code API in different languages.

Its basic implementation principle:

After the service is started, the gRPC client sends a name resolution request to the name server. The name will be resolved to one or more IP addresses. Each IP address indicates whether it is a server address or a load balancer address, and which client load balancing policy is to be used. or service configuration.

The client instantiates the load balancing policy. If the address returned by the resolution is the load balancer address, the client will use the grpclb policy. Otherwise, the client will use the load balancing policy requested by the service configuration.

The load balancing policy creates a subchannel for each server address.

When there is an RPC request, the load balancing policy determines which sub-channel, the grpc server, will receive the request. When the available server is empty, the client’s request will be blocked.

According to the design ideas officially provided by gRPC, based on the in-process LB solution (that is, the second case, Alibaba’s open source service framework Dubbo also uses a similar mechanism), combined with distributed consistent components (such as Zookeeper, Consul, Etcd), gRPC services can be found A viable solution for discovery and load balancing. Next, taking the GO language as an example, we will briefly introduce the key code implementation based on Etcd3:

4.1 dubbo

As described above, dubbo supports grpc. The solution is similar to the solution proposed in 3.1 of this article, but Alibaba provides a complete set of microservice systems, including the registration center nacas, dubbo, and sentinel all support grpc.

4.2 springcloud

This solution is also similar to Chapter 3.2, which integrates net.devh.grpc.
The latest version of this plug-in also supports springcloud family bucket. For details, please refer to github:
https://github.com/yidongnan/grpc-spring-boot-starter.
If it is a heterogeneous language, you need to integrate the sidecar in spring cloud to realize service discovery. Here, it only supports Java to call other heterogeneous languages. If you need other languages to also support mutual calls, you need to correspond to the language according to the plan 2 of the official open source component. to implement the corresponding components

4.3 istio

What is Istio: Istio is an open source project jointly developed by Google/IBM/Lyft. The first release 0.1.0 was released in May 2017. The official definition is:

Istio: An open platform to connect, manage and secure microservices.

According to the definition given in the isito documentation:

Istio provides a simple way to establish a network of deployed services, with load balancing, service-to-service authentication, monitoring and other functions, without changing any service code.

Simply put, with Istio, your service no longer needs any microservice development framework (typically such as Spring Cloud, Dubbo), nor does it need to implement various complex service governance functions by yourself (many Spring Cloud and Dubbo cannot provide it, so you need to do it yourself). As long as a service’s clients and servers have simple direct network access, they can gain a full range of functionality by delegating the network layer to Istio.
Key features of Istio:

  • Automatic zone-aware load balancing and failover for HTTP/1.1, HTTP/2, gRPC and TCP traffic.
  • Fine-grained control of traffic behavior through rich routing rules, fault tolerance and fault injection.
  • Pluggable policy layer and configuration API supporting access control, rate limiting and quotas.
  • Automatic measurement, logging and tracking of all traffic within the cluster, including cluster ingress and egress.
  • Secure service-to-service authentication with strong identity between services in the cluster.

It can be roughly understood as: Istio = microservice framework + service governance
The following is the official topology diagram of Istio:

The premise here is that k8s is used, and istio can be seamlessly integrated in k8s. I will not describe the specific steps here. For details, you can refer to the link below to practice service mesh gRPC metrics using Istio and Envoy.

5 grpc interceptor

grpc comes with its own authentication, but sometimes you need to do some operations before or after the call, such as recording monitoring information, or transparently transmitting headers, etc. In this case, you need to use grpc’s interceptor, here only in java language Let’s talk about interceptor usage.

5.1 server interceptor

public class MyServerInsterceptor implements ServerInterceptor{


    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
                                                                 Metadata headers, ServerCallHandler<ReqT, RespT> next) {
      
        return next.startCall(call,headers);
    }
}

Global interceptors can be set here

@Configuration
public class GrpcOpenConfig {

    //grpc-spring-boot-starter provides @GrpcGlobalInterceptor to allow server-side interceptors to be registered with all
    //server stubs, we are just taking advantage of that to install the server-side gRPC tracer.
    @Bean
    ServerInterceptor grpcServerInterceptor() {
        return new MyServerInterceptor();
    }

    @Bean
    public GlobalServerInterceptorConfigurer globalInterceptorConfigurerAdapter(ServerInterceptor grpcServerInterceptor) {
        return registry -> registry.addServerInterceptors(grpcServerInterceptor);
    }
}

At the same time, if grpc-spring-boot-starter is integrated, you can also use @GrpcGlobalInterceptor to add a global interceptor. You need to add this annotation to the class name.

5.2 client interceptor

public class MyClientInterceptor implements ClientInterceptor {


    Metadata.Key<String> token = Metadata.Key.of("token", Metadata.ASCII_STRING_MARSHALLER);

    @Override
    public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method,
            CallOptions callOptions, Channel next) {
        return new SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {

            @Override
            public void start(Listener<RespT> responseListener, Metadata headers) {
                //Here is the value of the token you get after logging in
                headers.put(token, "A2D05E5ED2414B1F8C6AEB19F40EF77C");
                super.start(new SimpleForwardingClientCallListener<RespT>(responseListener) {
                    @Override
                    public void onHeaders(Metadata headers) {
                        super.onHeaders(headers);
                    }
                }, headers);
            }
        };
    }
}

Global interceptors can be set here

@Order(Ordered.LOWEST_PRECEDENCE)
@Configuration
@Slf4j
public class GrpcOpenTracingConfig {
    //We also create a client-side interceptor and put that in the context, this interceptor can then be injected into gRPC clients and
    //then applied to the managed channel.
    @Bean
    ClientInterceptor grpcClientInterceptor() {
        return new MyclientInterceptor();
    }

    @Bean
    public GlobalClientInterceptorConfigurer globalInterceptorConfigurerAdapter(ClientInterceptor grpcClientInterceptor) {
        return registry -> registry.addClientInterceptors(grpcClientInterceptor);
    }

}

At the same time, if grpc-spring-boot-starter is integrated, you can also use @GrpcGlobalInterceptor to add a global interceptor. You need to add this annotation to the class name.

6 grpc monitoring full link

Regarding full-link monitoring, you can refer to my full-link blog series
Microservice full-link tracking: grpc integrates zipkin
Microservice full-link tracking: jaeger integrates grpc
Microservice full-link tracking: jaeger integrates istio and is compatible with uber-trace-id and b3

7 grpc monitoring prometheus

If grpc-spring-boot-starter is integrated, you only need to visit http://service domain name/actuator/prometheus to see grpc-related monitoring indicators.

If grafana is integrated, you can see the following effect:

8 grpc circuit breaker

There are several options for grpc circuit breakers:
1. istio circuit breaker
Refer to the related blog istio-circuit breaker example
2. Hystrix
Refer to my blog grpc circuit breaker hystrix
3. sentinel
grpc circuit breaker sentinel

9 grpc high concurrency optimization warm-up

Here you can refer to my blog springcloud online publishing timeout grpc optimization

10 grpc error collection and solutions

Refer to my blog: grpc error report collection and solutions
grpc pit: Could not find TLS ALPN provider; no working netty-tcnative

To be continued