SpringBoot integrates grpc to realize microservices

foreword

In the traditional SpringCloud implementation of microservices, we usually use the SpringCloud OpenFeign component to complete the RPC calls between microservices in the way of RESTFUL API calls; the microservices implemented in SpringCloud using the RESTFUL API are in actual projects It is still very common; it is relatively simple to implement, and it also supports more components for processing such as service fusing in RPC calls; general Spring Cloud uses OpenFeign through HTTP; today we will introduce you to this article. gRPC, a more extensive RPC call method applied in cloud native; and see how SpringBoot integrates gRPC to implement a microservice.

gRPC

gRPC, also a kind of RPC framework, can be regarded as g-RPC; it is a high-performance, open-source and general-purpose RPC framework, developed based on the ProtoBuf (Protocol Buffers) serialization protocol, and supports many development languages. Oriented to server and mobile terminals, based on HTTP/2 design, it brings features such as bidirectional flow, flow control, header compression, and multiplexed requests on a single TCP connection. These features make it perform better on mobile devices, saving power and space. The way of gRPC is somewhat familiar with RMI in JAVA technology. ProtoBuf will generate a Stub (stub) similar to RMI technology; the Stub includes protocol parsing Marshal and Unmarshel, as well as the interface and implementation class for the protocol to communicate through Tcp/IP. When calling, we directly call the interface of this implementation class to complete the detailed implementation of communication with the target and remote calling; the difference from RMI is that the protocol method is different, and gRPC uses the Protobut protocol for data transmission;

As shown below;

Comparison of gRPC and RESTFUL

gRPC Advantages

performance

gRPC messages are serialized using Protobuf, an efficient binary message format. Protobuf can be serialized very quickly on both server and client. Protobuf serialization produces a small payload, which is important in bandwidth-constrained scenarios such as mobile applications.

gRPC is designed for HTTP/2 (the major version of HTTP), which has huge performance advantages over HTTP 1.x:

  • Binary framing and compression. The HTTP/2 protocol is compact and efficient both in sending and receiving.
  • Multiplex multiple HTTP/2 calls over a single TCP connection. Multiplexing eliminates head-of-line blocking.

HTTP/2 is not exclusive to gRPC. Many request types, including HTTP APIs with JSON, can use HTTP/2 and benefit from its performance improvements.

code generation

All gRPC frameworks provide first-class support for code generation. The .proto file is the core file of gRPC development, which defines the contract of gRPC services and messages. From this file, the gRPC framework generates service base classes, messages, and a complete client.

By sharing .proto files between server and client, messages and client code can be generated end-to-end. Code generation for the client side eliminates duplication of messages on the client and server, and creates strongly typed clients for you. Not having to write clients can save a lot of development time in applications with many services.

Strict specification

There is no formal specification for an HTTP API with JSON. Developers debate the best format for URLs, HTTP verbs, and response codes.

The gRPC specification specifies the format that gRPC services must follow. gRPC removes the hassle and saves developers time because gRPC is consistent across platforms and implementations.

streaming

HTTP/2 provides the foundation for long-term real-time communication streams. gRPC provides first-class support for streaming over HTTP/2.

gRPC services support all streaming combinations:

  • unary (no streaming)
  • Server to client streaming
  • Client to server streaming
  • two-way streaming

Deadlines/Timeouts and Cancellations

gRPC allows clients to specify how long they are willing to wait for an RPC to complete. The deadline is sent to the server, and the server can decide what to do if the deadline is exceeded. For example, a server might cancel an ongoing gRPC/HTTP/database request after a timeout.

Propagating deadlines and cancellations through gRPC subcalls helps enforce resource usage limits.

gRPC usage process

Define standard proto files

generate standard code

The server uses the generated code to provide services

The client calls the service using the generated code

SpringBoot basic gRPC

Define the proto file as a service standard

syntax = "proto3";

package service;
option java_multiple_files = false;
option java_package = "com.joinsun.application.dubbo.demo.protobuf";
option java_outer_classname = "HelloGrpcServiceProto";
option go_package = "./hello_grpc";

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  rpc SayHelloOutStream (HelloRequest) returns (stream HelloReply) {}
  rpc SayHelloInStream (stream HelloRequest) returns (HelloReply) {}
  rpc SayHelloBothStream (stream HelloRequest) returns (stream HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}


message HelloRequest {

string name = 1;

}



message HelloReply {

string message = 1;

}

 

generate standard code

Add the proto file processing plug-in to pom.xml, so that when maven builds the springboot project, it will automatically build the proto file

In the build-"plugins section of pom.xml, add plugins that support proto files

    <plugin>
        <groupId>org.xolstice.maven.plugins</groupId>
        <artifactId>protobuf-maven-plugin</artifactId>
        <version>0.5.0</version>
        <configuration>
            <protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
            <pluginId>grpc-java</pluginId>
            <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
            <outputDirectory>src/main/java</outputDirectory>
            <clearOutputDirectory>false</clearOutputDirectory>            
        </configuration>
        <executions>
            <execution>
                <goals>
                    <goal>compile</goal>
                    <goal>compile-custom</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

In the above plug-in, some related attribute parameters; as follows

<properties>
    <dubbo.protobuf.verion>2.7.14</dubbo.protobuf.verion>
    <dubbo.compiler.version>0.0.2</dubbo.compiler.version>
    <grpc.version>1.6.1</grpc.version>
    <protobuf.version>3.3.0</protobuf.version>
    <protobuf.format.version>1.2</protobuf.format.version>
</properties>

Compiled content

Write server-side code (implement business logic)

add dependency

Import the proto file generated after the above compilation; write the business logic code of the service provider

Add the dependency of grpc to the pom file

        <!--    GRPC    -->
        <dependency>
            <groupId>org.lognet</groupId>
            <artifactId>grpc-spring-boot-starter</artifactId>
            <version>${grpc-spring-boot-starter.version}</version>
        </dependency>

write business code

@GRpcService
public class OperateImpl extends GreeterGrpc.GreeterImplBase {
    @Override
    public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
String msg = String.format("Protobuf: Hello, %s %s", request.getName(), DateUtil.formatDateTime(DateUtil.date()));

return HelloGrpcServiceProto.HelloReply.newBuilder().setMessage(msg).build();
     }
}

Write consumer code (call service)

add dependency

Import the proto file generated after the above compilation; write the business logic code of the service provider

Add the dependency of grpc to the pom file

        <!--    GRPC    -->
        <dependency>
            <groupId>org.lognet</groupId>
            <artifactId>grpc-spring-boot-starter</artifactId>
            <version>${grpc-spring-boot-starter.version}</version>
        </dependency>

call service

@Component
@Slf4j
public class GRpcService {
    private Channel serverChannel;

    @Setter
    @Value("${grpc.client.grpc-server.host:localhost}")
    private String host;

    @Setter
    @Value("${grpc.client.grpc-server.port:8098}")
    private int port;

    @PostConstruct
    public void init(){
        ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build();
        this.serverChannel = managedChannel;
    }

    public String sayHello(String word){
        GreeterGrpc.GreeterStub stub = GreeterGrpc.newBlockingStub(serverChannel);

        HelloGrpcServiceProto.HelloReply helloReply = stub.sayHello(HelloGrpcServiceProto.HelloRequest.newBuilder().setName(word).build());

        return helloReply.getMessage();
    }

    public String sayHelloStream(String word){
        GreeterGrpc.GreeterStub stub = GreeterGrpc.newStub(serverChannel);

        stub.sayHelloOutStream(HelloGrpcServiceProto.HelloRequest.newBuilder().setName(word+"-Java-Out").build(), new StreamObserver<HelloGrpcServiceProto.HelloReply>() {
            @Override
            public void onNext(HelloGrpcServiceProto.HelloReply helloReply) {
                log.info("Receiver[Out] {}", helloReply.getMessage());
            }

            @Override
            public void onError(Throwable throwable) {
                log.info("Error[Out] {}", throwable);
            }

            @Override
            public void onCompleted() {
                log.info("Receive[Out] finish");
            }
        });

        StreamObserver<HelloGrpcServiceProto.HelloRequest> requestStreamObserver =
                stub.sayHelloInStream(new StreamObserver<HelloGrpcServiceProto.HelloReply>() {
            @Override
            public void onNext(HelloGrpcServiceProto.HelloReply helloReply) {
                log.info("Receiver[In] {}", helloReply.getMessage());
            }

            @Override
            public void onError(Throwable throwable) {
                log.info("Error[In] {}", throwable);
            }

            @Override
            public void onCompleted() {
                log.info("Receive[In] finish");
            }
        });

        for( int idx = 1; idx <= 10; idx ++) {
            requestStreamObserver.onNext(HelloGrpcServiceProto.HelloRequest.newBuilder().setName(word+"-Java-In-"
                    + idx).build());
        }

        requestStreamObserver.onCompleted();

        requestStreamObserver =
                stub.sayHelloBothStream(new StreamObserver<HelloGrpcServiceProto.HelloReply>() {
            @Override
            public void onNext(HelloGrpcServiceProto.HelloReply helloReply) {
                log.info("Receiver[Both] {}", helloReply.getMessage());
            }

            @Override
            public void onError(Throwable throwable) {
                log.info("Error[Both] {}", throwable);
            }

            @Override
            public void onCompleted() {
                log.info("Receive[Both] finish");
            }
        });

        for( int idx = 1; idx <= 10; idx ++) {
            requestStreamObserver.onNext(HelloGrpcServiceProto.HelloRequest.newBuilder().setName(word+"-Java-Both-"
                    + idx).build());
        }

        requestStreamObserver.onCompleted();

        return "OK";
    }
}

In the above code for RPC remote calls by consumers, we demonstrate two calls, one is a normal call, and the other is a one-way flow call;

Deploy the server and consumer

Start both the server and the client, and through the call of the GRpcService on the consumer side, the remote call of grpc can be realized

conclusion

This article introduces gRpc, a very widely used RPC calling method in cloud native, and introduces the actual combat case of gRPC calling in java language by integrating gRPC through Springboot; the calling of gRPC is cross-language, interested friends You can use the GO language to implement server-side calls to Java; by comparison, you will find that Go's call support for gRPC is more convenient than Java.

Thank you for your continued attention! ! !

Guess you like

Origin blog.csdn.net/inthirties/article/details/126761747