版权声明:本文为博主原创文章,转载请注明出处。https://blog.csdn.net/u012319493/article/details/82935290

GRPC 是一种二进制,性能好,跨语言,还灵活,同时可以进行服务治理的多快好省的 RPC 框架,唯一的不足是要写协议文件。

GRPC 序列化使用 Protocol Buffers,网络传输使用 HTTP 2.0,服务治理可以使用基于 Envoy 的 Service Mesh。

Protocol Buffers

GRPC 要同时做到使用二进制、跨语言,需要双方定义一个协议文件 .proto,规定好双方沟通的专业术语。

以购买专栏为例:

syntax = “proto3”;    # 使用 proto3 语法
package com.geektime.grpc
option java_package = “com.geektime.grpc”;
message Order {            # 消息类型,发出去的参数
  required string date = 1;    #   字段都有唯一的标识,压缩时只需传输数字标识即可
  required string classname = 2;
  required string author = 3;
  required int price = 4;
}

message OrderResponse {          # 消息类型,返回的结果
  required string message = 1;
}

service PurchaseOrder {    # 定义 Service
  rpc Purchase (Order) returns (OrderResponse) {}  #  RPC 调用
}

类型中的字段都有唯一的标识,压缩时只需传输数字标识即可。

无论使用什么语言,都有相应的工具生成客户端和服务端的 Stub 程序,这样客户端就可以像调用本地一样调用远程服务。

协议约定问题

Protocol Buffers 是一款压缩率极高的序列化协议。对于 int 类型,Protocol Buffers 使用变长整数形式。

每一个 Byte 的 8 位,最高位都有特殊的含义:

  • 为 1,表示后续的 Byte 也属于该数。
  • 为 0,该数到此结束。

每个字段,使用 TLV(Tag, Length, Value)存储方式。其中,Tag = (field_num << 3) | wire_type。field_num 是在 proto 文件中,给每个字段指定的唯一数字标识,wire_type 标识后面的数据类型。
趣谈谈网络协议---跨语言类RPC协议:交流之前,双方先来个专业术语表-LMLPHP
例如,对于 string author = 3,field_num 为 3,string 的 wire_type 为 2,有 11 << 3 | 10 = 11000 | 10 = 11010 = 26;Value 为 “liuchao”,如果使用 UTF-8 编码,长度为 7 个字符。所以,最终存储形式为(26, 7, liuchao)。在序列化效率方面做到了极致。

在灵活性方面,这种基于协议文件的二进制压缩协议存在更新不便的问题。Protocol Buffers 考虑了兼容性。协议文件中的每一个字段都有修饰符,如:

  • required:该值不能为空。
  • optional:可选字段,不设置时使用默认值。
  • repeated:可重复 0 到多次。

网络传输问题

如果时 Java 技术栈,GRPC 的客户端和服务器之间通过 Netty Channel 作为数据通道,每个请求被封装称 HTTP 2.0 的 Stream。

Netty 是一个高效的基于异步 IO 的网络传输框架。

HTTP 2.0 的传输:
趣谈谈网络协议---跨语言类RPC协议:交流之前,双方先来个专业术语表-LMLPHP

由于基于 HTTP 2.0,GRPC 和 其他 RPC 不同,可定义四种服务方法。

1、最常用的单向 RPC,客户端像服务端发送一个请求,并获取一个应答,就像一次普通函数的调用。

rpc SayHello(HelloRequest) returns (HelloResponse){}

2、服务端流式 RPC,服务端返回一批结果。

rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){}

3、客户端流式 RPC,客户端发出一批请求。

rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {}

4、双向流式 RPC,两边分别通过一个读写数据流来发送一系列消息。

rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){}

基于 HTTP 2.0,客户端和服务端之间的交互方式比较丰富,不仅可以单向远程调用,还可实现当服务端状态改变时,主动通知客户端。

服务发现和治理问题

GRPC 本身没有提供服务发现机制,需借助 Envoy,不仅时负载均衡器,还是高性能的 C++ 写的 Proxy 转发器,可以配置非常灵活的转发规则。

规则可以是静态的,放在配置文件中,启动时加载。Envoy 支持热加载和热重启。

最好将规则设置为动态的,放在统一的地方维护,这个统一的地方是服务发现(Discovery Service)。

配置中往往配置 4 项:

  • listener,监听端口。
  • endpoint,目标 IP 和端口。
  • cluster,是具有完全相同行为的多个 endpoint。从 cluster 到 endpoint 的过程为负载均衡。
  • route,有时多个 cluster 有类似的功能,但版本号不同,可通过 route 规则将请求路由到某一版本号,即某个 cluster。

服务中心需要实现 Envoy 的 API,Envoy 可主动去服务发现中心拉取转发策略。Envoy 在控制面和服务发现中心沟通时,使用 GRPC。

Envoy 配置规则:

  • 配置路由策略。例如后端服务有 2 个版本,可通过配置 Envoy 的 route,设置两个版本间,即 两个 cluster 间的 route 规则,一个占 99% 的流量,另一个占 1%。
  • 负载均衡策略。对于一个 cluster 下的多个 endpoint,可配置负载均衡机制和健康检查机制。
    趣谈谈网络协议---跨语言类RPC协议:交流之前,双方先来个专业术语表-LMLPHP
    节点的变化均会上传到注册中心,策略都可通过注册中心下发,所以,注册中心可称为注册管理中心。

未来服务治理的趋势 Service Mesh,应用之间的相互调用、服务之间的治理完全由 Envoy 代理,完全将服务治理抽象到平台层解决。

趣谈谈网络协议---跨语言类RPC协议:交流之前,双方先来个专业术语表-LMLPHP

10-04 12:46