gRPC-谷歌高性能RPC框架

概要

RPC远程过程访问

gPRC具有标准化、可通用和跨平台的特点

进程间通信,通常是指一个应用实例调用另外一个应用实例所提供的服务,而这两个应用都运行在自己独立的进程中,通过网络彼此交换信息的过程。

契约优先

优点

高效进程间通信

简单且定义良好的服务接口和模式,编译阶段发现问题

属于强类型调用

支持多语言

支持双工通信

缺点

gRPC不适合面向外部的服务

服务定义变更,会出现复杂的开发流程

gRPC生态系统相对较小

Protobuf

Google提供一个具有高效的协议数据交换格式工具库(类似Json)

Protobuf 时间效率和空间效率是JSON的3到5倍

客户端与服务端通信使用 HTTP2 协议

安装

1.安装Protobuf编译器

Protobuf运行环境需安装Protobuf编译器

下载地址:

windows 配置环境变量

  1. 新建系统变量 PROTOBUF_HOME 变量值 是 protobuf 编译器解压目录。
  2. 编辑Path环境变量,添加 %PROTOBUF_HOME%\bin

验证是否配置成功

打开CMD,输入protoc,输出一些列参数说明,则说明安装好了

2.安装IDEA Protobuf插件

打开IDEA,进入插件市场,搜索protobuf,如下图所示,安装即可

pS1Q2C9.png

使用

服务端开发流程

  1. Maven增加gRPC依赖坐标系

  2. 引入protobuf-maven-plugin插件

  3. 编写proto服务定义文件

  4. 实现服务端业务逻辑

  5. 开发服务端启动器

maven 依赖

<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-netty-shaded</artifactId>
    <version>1.42.0</version>
</dependency>

<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-protobuf</artifactId>
    <version>1.42.0</version>
</dependency>

<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-stub</artifactId>
    <version>1.42.0</version>
</dependency>

<dependency> <!-- 可选 necessary for Java 9+ -->
    <groupId>org.apache.tomcat</groupId>
    <artifactId>annotations-api</artifactId>
    <version>6.0.53</version>
    <scope>provided</scope>
</dependency>

<!-- protobuf代码生成插件 -->
<plugin>
    <groupId>org.xolstice.maven.plugins</groupId>
    <artifactId>protobuf-maven-plugin</artifactId>
    <version>0.6.1</version>
    <configuration>
        <protocArtifact>com.google.protobuf:protoc:3.17.3:exe:${os.detected.classifier}</protocArtifact>
        <pluginId>grpc-java</pluginId>
        <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.42.0:exe:${os.detected.classifier}</pluginArtifact>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>compile</goal>
                <goal>compile-custom</goal>
            </goals>
        </execution>
    </executions>
</plugin>

引入maven 完成后,在代码的main目录下,创建proto文件夹(约定)。

maven 插件会自动扫描,proto 文件夹下的 proto 后缀文件,进行代码生成。

IDEA插件就是对 proto 文件提供语法检查等编辑器支持。

编辑好proto文件后,点击IDEA右侧maven -> 找到需生成的服务 -> Plugins -> protobuf -> protobuf:complie -> protobuf:complie-custom 生成RPC代码

生成的代码在,target 目录对应配置的包下,需要将生成的java代码,移动到src下

服务端代码demo

// 自己建一个 service类,继承 Grpc 下的 实现类
public class TestService extends TestServiceGrpc.TestServiceImplBase {

    @Override
    public void hello(TestProto.StringRequest request, StreamObserver<TestProto.StringResponse> responseObserver) {
        String name = request.getName();
        TestProto.StringResponse response = TestProto.StringResponse.newBuilder().setResult("你好," + name).build();
        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }

}

客户端开发流程

客户端与服务端依赖的jar是相同的

也是main目录下创建 proto 文件夹,然后将proto文件复制到客户端。

然后用maven生成代码,跟服务端一样,如果是同样的语言进行开发,直接从服务端复制过去也可以。

客户端发送请求代码

// 类似 jdbc 一样的套路代码
ManagedChannel channel = ManagedChannelBuilder.forAddress(host, serverPort).usePlaintext()
        .build();
try {
    TestServiceGrpc.TestServiceBlockingStub blockingStub = TestServiceGrpc.newBlockingStub(channel);
    Test.StringResponse response = blockingStub.hello(Test.StringRequest.newBuilder().setName("小黑").build());
    System.out.println(response.getResult());
}finally {
    channel.shutdown();
}

Protobuf 文件详解

proto 文件

// 使用proto3语法
syntax = "proto3";
// 生成多个类,设置为否
option java_multiple_files = false;
// 生成java类所在的包
option java_package = "com.songjh.demo";
// 生成外层类类名
option java_outer_classname = "Test";
// 逻辑包名,实际不会加到类上,就是给 proto 文件的逻辑包名
package songjh;
// service服务,用于描述要生成的API接口,类似于接口类
service TestService {
    //rpc 方法名( 参数类型)  returns (返回类型)
    rpc list(TestRequest) returns (TestResponse) {}
    rpc hello(StringRequest) returns (StringResponse){}
}
/*
    消息,类似Java的"实体类"
    名字,对应于生成代码后的类名
    每一个消息都对应生成一个类,根据java_multiple_files设置不同文件数量也不同
 */
message NewsRequest {
    /*
        字段:类型 名称 = 索引值(id)
        每个字段都要定义唯一的索引值,这些数字是用来在消息的二进制格式中识别各个字段的。
        一旦开始使用就不能够再改变,最小的标识号可以从1开始,最大到2^29 - 1, 或 536870911。
        不可以使用 [19000-19999]的标识号, Protobuf协议实现中对这些进行了预留。
        切记:要为将来有可能添加的、频繁出现的标识号预留一些标识号。可以1 ,10,,20,  30 这样初始化。
    */
    string date = 1;
}
message TestResponse {
    //repeated说明是一个集合(数组),数组每一个元素都是News对象
    repeated News news = 1; //List<News> getNewsList();
}
//News新闻实体对象
message News{
    int32 id = 1;              // int id = 0;
    string title = 2;          // String title = "";
    int64 createTime = 3; // long createTime = 0l;
}

message StringRequest{
    string name = 1;
}

message StringResponse{
    string result = 1;
}

生成代码

父类类名说明
DemoMess消息类的大类
DemoMessDemoOrBuilder消息类与构造器接口
DemoMessDemoRequestOrBuilder消息类与构造器接口
DemoMessDemoResponseOrBuilder消息类与构造器接口
DemoMessDemo具体的消息类实现
DemoMessDemoRequest具体的消息类实现
DemoMessDemoResponse具体的消息类实现
DemoServiceGrpcgRPC通信类的集合
DemoServiceGrpcXXXDescriptorSuppliergRPC通信用的描述符文件 (元数据)
DemoServiceGrpcDemoServiceBlockingStub同步通信客户端存根,产生阻塞,支持一元与服务端流数据通信
DemoServiceGrpcDemoServiceFutureStub异步通信客户端存根,基于Guava Future实现不支持流式处理
DemoServiceGrpcDemoServiceStub异步通信客户端存根,支持双向流式传输
DemoServiceGrpcNewsServicelmplBase服务器端的骨架类,继承这个类实现业务逻辑

通信模式

一元RPC通信模式

客户端向服务器发送单个请求并获得单个响应

客户端使用 newBlockingStub 通信即可。

DemoServiceGrpc.newBlockingStub(channel);

服务端流式RPC通信模式

从客户端发起1次请求,会产生从服务器的多次响应

首先proto文件,service 定义中 rpc 方法的 返回值类型 前增加 stream ,如下

service SmsService {
    rpc test(TestRequest) returns (stream TestResponse) {}
}

一般来说客户端传过来的是个 List

服务端代码如下

// 循环遍历客户端传过来的 List
for(String xxx : xxxList) {
    Demo.XXXResponse response = Demo.XXXResponse.newBuilder().setXX().build();
    // 向客户端返回一次响应
    responseObserver.onNext();
}
// 服务器端都处理完了,告诉客户端服务端都完事了
responseObserver.onCompleted();

客户端还是用newBlockingStub。

流式的返回值是 Iterator 。

客户端流式RPC通信模式

从客户端发起多次请求,产生从服务器的1次响应

例如导入多条数据,最后返回一次结果。

客户端流式RPC,服务端必须使用异步处理

首先proto文件客户端需要增加stream,如下

service TestService {
    rpc createString(stream TestRequest) returns (TestResponse) {}
}

服务端代码,必须用异步处理

public StreamObserver<TestProto.TestRequest> test(StreamObserver<TestProto.TestResponse> responseObserver) {
    /**
     * 异步通信基于responseObserver事件回调
     */
    return new StreamObserver<TestProto.TestRequest>() {
        @Override
        //接收到客户端发来的单个请求时,触发onNext
        public void onNext(TestProto.TestRequest request) {
            // 处理业务请求
        }

        @Override
        public void onError(Throwable throwable) {
            throwable.printStackTrace();
        }

        //客户端传输完毕时,完成消息统计
        @Override
        public void onCompleted() {
            // 服务端返回一次消息结果
            responseObserver.onNext()
            responseObserver.onCompleted();
        }
    };

}

双向流式RPC通信模式

双向即是 客户端和服务端都是多对多,其实就是上述 客户端和服务端流式RPC通信代码结合。

proto文件客户端和服务端都需要增加stream

service SmsService {
    rpc test(stream testRequest) returns (stream testResponse) {}
}

SpringBoot 集成 gRPC

maven依赖,插件依赖跟之前一样没有变化

<dependency>
    <groupId>net.devh</groupId>
    <artifactId>grpc-server-spring-boot-starter</artifactId>
    <version>2.13.0.RELEASE</version>
</dependency>

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

依然是在src目录下创建 proto 文件夹,然后在该文件夹下创建proto文件。

在创建 service 类上,增加 @GrpcService 注解。

yml配置

# gRPC 服务端设置,服务端开启的端口
grpc:
    server:
        port: 9090

# gRPC 客户端配置
grpc:
    client:
        grpc-server: #自定义一个gRPC服务名
            address: 'static://127.0.0.1:9090'  # static 表示静态ip直接访问
            negotiationType: plaintext  # 传输类型设置成文本

客户端使用时,可以直接依赖注入,通过@GrpcClient 注解。

@GrpcClient("grpc-server")
private DemoServiceGrpc.DemoServiceBlockingStub newsStub;

Eureka 集成 gRPC

eureka server 没变化,也不用额外引入maven 或单独配置。

gRPC 的 server,也作为 eureka client ,注册到eureka 上。

gRPC 的客户端和服务端 需引入maven 配置如下

<dependency>
    <groupId>net.devh</groupId>
    <artifactId>grpc-server-spring-boot-starter</artifactId>
    <version>2.13.0.RELEASE</version>
</dependency>
<!-- 如遇到版本冲突,则可能是sc依赖的guava版本过低 -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0-jre</version>
</dependency>

server 端代码编写,跟springboot 编写一样,就是配置不一样

grpc:
   server:
       port: 0  # 设置为0 表示使用给一个未被占用的随机端口,会被上传eureka,所以不用配

客户端配置

grpc:
    client:
        g-server-service:  # 服务端名称,spring.application.name
            negotiationType: plaintext  #代表文本传输

客户端代码

// 这个名字要保持一致,调用哪个服务的方法
@GrpcClient("g-server-service")
private DemoServiceGrpc.DemoServiceBlockingStub newsStub;
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宋小黑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值