gRPC基础知识

参考资料:

基础知识

gRPC是一个由google设计开发基于HTTP/2协议和Protobuf序列化协议的的高性能、多语言、通用的开源 RPC 框架。

传统rpc对比Grpc

  • 传统RPC框架:使用各种协议和编码方式进行通信,可能导致跨语言通信困难、性能不佳等问题;
  • GRPC框架:使用Google开发的ProtoBuf进行序列化、并通过http/2(多路复用)进行通信,通信效率更加高效;

在这里插入图片描述

性能

gRPC 消息使用 Protobuf(一种高效的二进制消息格式)进行序列化。 Protobuf 在服务器和客户端上可以非常快速地序列化。 Protobuf 序列化产生的有效负载较小,这在移动应用等带宽有限的方案中很重要。

gRPC 专为 HTTP/2(HTTP 的主要版本)而设计,与 HTTP 1.x 相比,HTTP/2 具有巨大性能优势:

  • 二进制组帧和压缩。 HTTP/2 协议在发送和接收方面均紧凑且高效。
  • 在单个 TCP 连接上多路复用多个 HTTP/2 调用。 多路复用可消除队头阻塞。

HTTP/2 不是 gRPC 独占的。 许多请求类型(包括具有 JSON 的 HTTP API)都可以使用 HTTP/2,并受益于其性能改进。

HTTP/2

  • HTTP/1.x 是超文本传输协议第1版,可读性好,但效率不高。
  • HTTP/2 是超文本传输协议第2版,是一个二进制协议

HTTP/2通用术语:

  • Stream: 流,一个双向流,一条连接可以有多个 streams。
  • Message: 逻辑上面的 request,response。
  • Frame:帧,HTTP/2 数据传输的最小单位。每个 Frame 都属于一个特定的 stream。一个 message 可能由多个 frame 组成。

HTTP/2连接上传输的每个帧(frame)都关联到一个流,一个连接上可以同时有多个流, 同一个流的帧按序传输,不同流的帧交错混合传输, 客户端、服务端双方都可以建立流,流也可以被任意一方关闭。
客户端发起的流使用奇数流ID,服务端发起的使用偶数流ID。

HTTP/2 特性

新的二进制格式(Binary Format)

HTTP/1 的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同。
基于这种考虑HTTP/2的协议解析决定采用二进制格式,实现方便且健壮。

多路复用(MultiPlexing)

  • HTTP/1 的request是阻塞的,如果想并发发送多个request,必须使用多个 TCP connection。
  • HTTP/2 一个TCP connection可以有多个streams(最大数量由参数SETTINGS_MAX_CONCURRENT_STREAMS控制), 多个streams 并行发送不同的请求的frames。

代码生成

所有 gRPC 框架都为代码生成提供一流支持。 .proto 文件是 gRPC 开发的核心文件,它定义 gRPC 服务和消息的协定。 通过此文件,gRPC 框架生成服务基类、消息和完整的客户端。

通过在服务器和客户端之间共享 .proto 文件,可以端到端生成消息和客户端代码。 客户端的代码生成消除了客户端和服务器上的消息重复,并为你创建强类型客户端。 无需编写客户端可在具有许多服务的应用程序中节省大量开发时间。

严格规范

具有 JSON 的 HTTP API 没有正式规范。 开发人员为 URL、HTTP 谓词和响应代码的最佳格式争论不休。

gRPC 规范对 gRPC 服务必须遵循的格式进行了规定。 gRPC 消除了争论并为开发人员节省了时间,因为 gRPC 在各个平台和实现中都是一致的。

流式处理

HTTP/2 为长期实时通信流提供基础。 gRPC 为通过 HTTP/2 进行流式传输提供一流支持。

gRPC 服务支持所有流式传输组合:

  • 一元(无流式传输)
  • 服务器到客户端流式传输
  • 客户端到服务器流式传输
  • 双向流式传输

引入

<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-netty-shaded</artifactId>
  <version>1.62.2</version>
  <scope>runtime</scope>
</dependency>
<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-protobuf</artifactId>
  <version>1.62.2</version>
</dependency>
<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-stub</artifactId>
  <version>1.62.2</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的代码生成,您可以将您的proto文件放在src/main/proto和src/test/proto目录中,并使用适当的插件。

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

简单使用

syntax = "proto3";   // 语法版本

// stub选项
option java_package = "com.xxx.grpc.api";// 指定生成的Java代码的包名
option java_outer_classname = "RPCDateServiceApi";//指定生成的Java类的外部类名
option java_multiple_files = true;// 指定是否为每个定义的服务生成多个文件

// 定义包名
package com.xxx.grpc.api;

// 服务接口定义,服务端和客户端都要遵守该接口进行通信
service RPCDateService {
    rpc getDate (RPCDateRequest) returns (RPCDateResponse) {}
}

// 定义消息(请求)
message RPCDateRequest {
    string userName = 1;
}

// 定义消息(响应)
message RPCDateResponse {
    string serverDate = 1;
}

Server端

        Server server = ServerBuilder.
                forPort(port)
                .addService( new RPCDateServiceImpl() )
                .build().start();
        System.out.println( "grpc服务端启动成功, 端口=" + port );
        server.awaitTermination();

Client端

ManagedChannel managedChannel = ManagedChannelBuilder.forAddress( host, serverPort )
									.usePlaintext()//这通常用于测试或内部网络中的通信,其中安全性不是主要关注点。
									.build();
        try {
            RPCDateServiceGrpc.RPCDateServiceBlockingStub rpcDateService = RPCDateServiceGrpc.newBlockingStub( managedChannel );
            RPCDateRequest rpcDateRequest = RPCDateRequest
                    .newBuilder()
                    .setUserName("XXX")
                    .build();
            RPCDateResponse rpcDateResponse = rpcDateService.getDate( rpcDateRequest );
            System.out.println( rpcDateResponse.getServerDate() );
        } finally {
            managedChannel.shutdown();
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值