SpringBoot整合grpc

目录

一、简介

二、下图是通信流程模型 

三、准备

四、环境搭建

1、服务端server

1)pom文件

2)创建proto用于生成proto目标文件

 3)服务端yml配置

4)创建GrpcServerService实现服务端接口

2、客户端client

1)pom文件

2)创建proto用于生成proto目标文件

 3)客户端yml配置

4)创建GrpcClientService客户端类

5)创建SimpleGrpcController

五、启动/测试

1、服务端测试

2、客户端测试 

六、问题

七、源码验证解析

客户端

服务端 


一、简介

之所以会说grpc是高性能框架,默认情况下,gRPC基于Netty进行服务端和客户端互通,使用Protocol Buffers进行传输,这是Google用于序列化结构化数据的成熟开源机制,基于proto3情况下它还是一个跨语言的RPC框架(目前支持Java、c++、Dart、Python、Objective-C、c#、lite-runtime (Android Java)、Ruby和JavaScript(来自协议缓冲区GitHub repo),以及来自golang/protobuf官方包的Go语言生成器) 

如果对grpc不够了解可以参考Introduction to gRPC | gRPC。

二、下图是通信流程模型 

SpringBoot整合grpc_第1张图片

  • 客户端(gRPC Stub)调用 A 方法,发起 RPC 调用。
  • 对请求信息使用 Protobuf 进行对象序列化压缩(IDL)。
  • 服务端(gRPC Server)接收到请求后,解码请求体,进行业务逻辑处理并返回。
  • 对响应结果使用 Protobuf 进行对象序列化压缩(IDL)。
  • 客户端接受到服务端响应,解码请求体。回调被调用的 A 方法,唤醒正在等待响应(阻塞)的客户端调用并返回响应结果。

三、准备

1、PROTOC下载及安装

下载地址

2、准备两个springboot项目,作为服务端和客户端

3、下载Apifox软件,用于直连服务端(可选)

下载地址

四、环境搭建

1、服务端server

1)pom文件

      
        
            org.springframework.boot
            spring-boot-starter
        
        
            io.grpc
            grpc-protobuf
            ${grpc.version}
        

        
            io.grpc
            grpc-stub
            ${grpc.version}
        
        
        
            net.devh
            grpc-server-spring-boot-starter
            2.13.1.RELEASE
        


    
    
        1.42.1
        3.7.1
    
    
        ${project.artifactId}-${project.version}
        
            
                kr.motd.maven
                os-maven-plugin
                1.6.2
            
        

        
            
            
                org.xolstice.maven.plugins
                protobuf-maven-plugin
                0.6.1
                
                    
                    
                    com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}
                    grpc-java
                    io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}


                
                
                    
                        
                            compile
                            compile-custom
                        
                    
                
            
        
    
2)创建proto用于生成proto目标文件

注意:proto文件需要创建在src/main/proto下,因为pom使用的是protoSourceRoot默认路径

SpringBoot整合grpc_第2张图片

创建Simple.proto 

syntax = "proto3"; // 协议版本

// 选项配置
option java_multiple_files = true;
//生成位置
option java_package = "com.na.model.proto";
option java_outer_classname = "SimpleProto";

service Simple {
  // 简单gRPC
  rpc OneToOne (MyRequest) returns (MyResponse) {
  }
}

message MyRequest {
  string name = 1;

  int32 value = 2;
}

message MyResponse {
  string message = 1;

  int64 result = 2;
}

 生成方式有两种一种是通过命令,这里使用maven插件生成compile和compile-custom

SpringBoot整合grpc_第3张图片

 编译后可在target下看到生成的相应的java类

SpringBoot整合grpc_第4张图片

 3)服务端yml配置

这里只贴出关键代码,其他配置根据实际情况来

# gRPC有关的配置,这里只需要配置服务端口号默认9090
grpc:
  server:
    port: 19898
spring:
  application:
    name: nacos-grpc

4)创建GrpcServerService实现服务端接口
package com.na.grpc.server;
import com.na.model.proto.MyRequest;
import com.na.model.proto.MyResponse;
import com.na.model.proto.SimpleGrpc;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;


/**
 * GrpcServerService.java中有几处需要注意:
 *
 * 是使用@GrpcService注解,再继承SimpleImplBase,这样就可以借助grpc-server-spring-boot-starter库将oneToOne暴露为gRPC服务;
 *
 * SimpleImplBase是前文中根据maven compile编译 proto文件自动生成的java代码,
 *
 * oneToOne方法中处理完毕业务逻辑后,调用responseObserver.onNext方法填入返回内容;
 *
 * 调用responseObserver.onCompleted方法表示本次gRPC服务完成;
 */
@GrpcService
@Slf4j
public class GrpcServerService extends SimpleGrpc.SimpleImplBase {

    @Override
    public void oneToOne(MyRequest request, StreamObserver responseObserver) {
        log.info("接收客户端数据{}", request);
        MyResponse response = MyResponse.newBuilder().setMessage( request.getName()).build();
        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }

}

2、客户端client

1)pom文件


        
            org.springframework.boot
            spring-boot-starter
        
        
            org.springframework.boot
            spring-boot-starter-web
          

        
            io.grpc
            grpc-protobuf
            ${grpc.version}
        
        
            io.grpc
            grpc-stub
            ${grpc.version}
        
        
        
            net.devh
            grpc-client-spring-boot-starter
            2.14.0.RELEASE
        
    

    
        1.42.1
        3.7.1
    
    
        ${project.artifactId}-${project.version}

        
            
                kr.motd.maven
                os-maven-plugin
                1.6.2
            
        

        
            
            
                org.xolstice.maven.plugins
                protobuf-maven-plugin
                0.6.1
                
                    
                    
                    com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}
                    grpc-java
                    io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}


                
                
                    
                        
                            compile
                            compile-custom
                        
                    
                
            
        
    
2)创建proto用于生成proto目标文件

与服务端操作一样,这里省略。。。。。。

 3)客户端yml配置

这里只贴出关键代码,其他配置根据实际情况来

server:
  port: 11278
  servlet:
    context-path: /
# grpc配置
grpc:
  # grpc clienT相关配置
  client:
    # 服务名(不同服务名可对应不同配置)
    # nacos-grpc是服务端配置的名字,GrpcClient注解会用到
    nacos-grpc:
#       gRPC服务端地址
#      address: 'dns://127.0.0.1:19898'
      address: 'static://127.0.0.1:19898'
      # 是否开启保持连接(长连接)
      enableKeepAlive: true
      # 保持连接时长(默认20s)
      keepAliveTimeout: 20s
      # 没有RPC调用时是否保持连接(默认false,可禁用避免额外消耗CPU)
      keepAliveWithoutCalls: false
      # 客户端负载均衡策略(round_robin(默认), pick_first)
      defaultLoadBalancingPolicy: round_robin
      # 通信类型
      # plaintext | plaintext_upgrade | tls
      # 明文通信且http/2 | 明文通信且升级http/1.1为http/2 | 使用TLS(ALPN/NPN)通信
      negotiationType: plaintext
4)创建GrpcClientService客户端类
package com.na.grpc.client;

import com.na.model.proto.MyRequest;
import com.na.model.proto.MyResponse;
import com.na.model.proto.SimpleGrpc;
import io.grpc.StatusRuntimeException;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.stereotype.Service;

/**
 * GrpcClientService类有几处要注意的地方:
 * 

* 用@Service将GrpcClientService注册为spring的普通bean实例; *

* 用@GrpcClient修饰SimpleBlockingStub,这样就可以通过grpc-client-spring-boot-starter库发起gRPC调用,被调用的服务端信息来自名为nacos-grpc服务端配置; *

* SimpleBlockingStub来自前文中根据helloworld.proto生成的java代码; *

* SimpleBlockingStub.oneToOne方法会远程调用nacos-grpc应用的gRPC服务; */ @Service @Slf4j public class GrpcClientService { @GrpcClient("nacos-grpc") private SimpleGrpc.SimpleBlockingStub simpleStub; public String oneToOne(final String name) { try { final MyResponse response = this.simpleStub.oneToOne(MyRequest.newBuilder().setName(name).build()); return response.getMessage(); } catch (final StatusRuntimeException e) { log.error("FAILED with " + e.getStatus().getCode().name() + ",and e:{}", e.getMessage()); return "FAILED with " + e.getStatus().getCode().name() + ",and e:" + e.getMessage(); } } }

5)创建SimpleGrpcController

定义了两种连接方法getOneToOne和testForAddress

package com.na.controller;

import com.na.base.BaseResponse;
import com.na.grpc.client.GrpcClientService;
import com.na.model.proto.MyRequest;
import com.na.model.proto.SimpleGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Description 测试grpc接口
 * @Author kele
 * @Data 2023/9/6 15:35
 */
@RestController
@RequestMapping("grpc")
public class SimpleGrpcController {
    @Autowired
    private GrpcClientService service;

    @GetMapping("getOneToOne")
    public BaseResponse getOneToOne() {
        return new BaseResponse(service.oneToOne("客户端kele连接"));
    }


    @GetMapping("testForAddress")
    public BaseResponse testForAddress() {
        ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 19898)
                .usePlaintext()
                .build();
        MyRequest request = MyRequest.newBuilder().setName("kele的访问").build();
        SimpleGrpc.SimpleBlockingStub stub = SimpleGrpc.newBlockingStub(channel);
        return new BaseResponse(stub.oneToOne(request));
    }

}

五、启动/测试

1、服务端测试

1)先启动服务端启动的netty端口为19898

2)使用Apifox连接服务端

创建grpc操作文档

可以看到,在Apifox中导入了Simple.proto帮我自动生成了客户端连接操作,自己只需要改一下19898端口和请求的参数

SpringBoot整合grpc_第5张图片

2、客户端测试 

1)启动客户端web端口为11278

2)直接通过web访问

这里访问的是getOneToOne方法, 地址http://localhost:11278/grpc/getOneToOne

另外的testForAddress方法可以自己玩一下生产一般不会那样写

SpringBoot整合grpc_第6张图片

六、问题报错

1、出现无法访问com.google.protobuf.GeneratedMessageV3 找不到com.google.protobuf.GeneratedMessageV,在pom中添加以下依赖。

        
            com.google.protobuf
            protobuf-java
            ${protobuf.version}
        
        
            com.google.protobuf
            protobuf-java-util
            ${protobuf.version}
        

2、出现:io.grpc.StatusRuntimeException: UNAVAILABLE

1、检查下IP是否能ping通,IP、端口 是否正确

2、Server是否打开

3、连接中如果有证书,证书是否有效

4、无证书的,是否写了明文连接,例如:

5、以上都没问题可以查看服务端是否添加了这个依赖,grpc-netty-shaded包中可能会存在core的冲突

        
            io.grpc
            grpc-netty-shaded
            ${grpc.version}
        

七、源码验证解析

客户端

1、客户端序列化,可以查看MyRequest

SpringBoot整合grpc_第7张图片

 2、在客户端调用SimpleGrpc.SimpleBlockingStub.oneToOne方法时,已经将name序列化传输了

SpringBoot整合grpc_第8张图片

3、再往下可以看到客户端ClientCalls中,采用的是异步的方式进行发送二进制数据,等结束执行后再进行判断是否执行结束,

SpringBoot整合grpc_第9张图片

SpringBoot整合grpc_第10张图片 waitAndDrain()即为等待,直到有一个Runnable,然后执行它和所有在它之后排队的Runnables。一次只能由一个线程调用。poll()方法用于从队列中取出并返回头部的元素,如果队列为空,则返回null。之后又将当前线程赋给了waiter

SpringBoot整合grpc_第11张图片

 用的是线程池,在服务端断点的情况下,后续请求会进入等待队列。

SpringBoot整合grpc_第12张图片

服务端 

待更新。。。。。。

你可能感兴趣的:(java,开发语言)