1. 什么是 RPC, 什么又是 gRPC
RPC (Remote Procedure call),远程过程调用是一个协议,可以让一个程序请求运行在另一台机子上的服务,类似于我们所熟悉的 HTTP 请求。
gRPC 是高性能的开源通用 RPC 框架,也称为 Google Remote Procedure Call,顾名思义即来自于谷歌的 RPC 框架。使用 HTTP/2 作为其传输协议,Protocol buffer 作为其 IDL (Interface Description Language),支持跨平台、跨语言。常应用于微服务间的通信或移动客户端与服务器间的通信。早期2015年谷歌将其用于内部微服务间的通信,而后将其开源,在2017年成为 CNCF(Cloud Native Computing Fundations)的孵化项目。
2. Protocol Buffer
作为 gRPC 的 IDL, Protocol buffer 是 Google 推出的序列化/反序列化协议,当前最新版本为 proto 3。在实际使用时将 gRPC 的 service 和 message 定义到 .proto 文件中,通过特定工具,可以生成一些语言的对应代码。相比于以往常见的 JSON 和 XML,它可以耗费更少的 CPU资源,且消息的体积更小,传输更快。
3. HTTP/2
作为 gPRC 默认使用的协议,相比于 HTTP/1.1,HTTP/2 拥有更多的优势:
- 二进制帧。 HTTP/2 的请求和响应消息被分割为体积更小的消息,且使用二进制的形式,这使得它可以传输地更快
- 流式通信。支持客户端同时发送多个请求,服务端同时发送多个响应。
- 请求头压缩。使用 HPACK 压缩算法,可使得请求头内容只含有和之前的请求不同的内容,无需每次请求都包含所有。
- 同步/异步处理。同时支持同步和异步处理,更灵活地支持不同的 rpc。
- 流量控制。
这些特性,使得 gRPC 可以使用更少的资源,拥有更快的传输速度。
4. Protobuf 如何编码
正如上面所述,使用 Protobuf 让传输的消息拥有更小的体积,具体体现在以下几个方面
4.1 请求头
HTTP的请求头是多个键值对构成的 map, 由于 HTTP/2请求头压缩的特性,在客户端和服务端之间维护一份静态表(Static table),里面包含了常见的 HTTP 请求头,那么在通信的时候只需传输其 key 即可,使用方通过 key 在静态表中取其固定的 Value。比如下图请求头,要传输 method: GET 这对键值对,实际只需要传输数字 “2” 即可。

静态表中有61个键值对。除此之外,还有动态表,作为静态表的补充,可以动态地将静态表中没有的键值对添加到动态表中,那么后续传输的键值对如果动态表已经有了,那么就可以直接使用数字代替。 最后使用霍夫曼编码,对值进一步压缩。
4.2 字段名
在一段39字节的 JSON 消息中
{"name":"John","id":1234,"sex":"MALE"}
对于的 .proto 文件中定义如下
message Person {
string name = 1;
uint32 id = 2;
enum SexType {
MALE = 0;
FEMALE = 1;
}
SexType sex = 3;
}
编码后的二进制对应关系如下,最后的体积可以压缩到11字节

每一个键值对都按照 字段名,类型,字段值 的顺序紧密排列。在 .proto 中每个字段等号后的数字,即完全转化为二进制数字。
4.3 字段值
第二部分的类型则对应上图的类型表格,基于上方表格,不同类型的字段值使用不同的处理方式。
字符串类型将每个字符转化为ASCII码,实际上不会节省空间。枚举类型相比于原先JSON的**“MALE”** 值则精简了许多,直接由二进制的 1 代替,仅占据 1 bit。对于数字 1234 的类型是 Varint。它是一种紧凑的数字表示方法,用一个或多个字节来表示1个数字,数字越小,则使用的字节越少。图中的 1234 由 1024+128+64+16+2 构成,表示为 00010011010010。具体的算法细节可参考
Encoding | Protocol Buffers | Google Developers
5. gRPC 通信架构
gRPC 可以分为如下三层(应用层,框架层,传输层)

在实际使用场景中,客户端和服务端需要使用工具基于 .proto 文件生成代码,生成的代码称为 stub。客户端发送请求时,就像调用本地函数一样去调用 stub,stub 将参数使用 ProtoBuf 序列化,通过 HTTP/2 发送给服务端,收到服务端响应后,使用 ProtoBuf 反序列化。
6. gRPC 的优缺点
6.1 优点
1. 性能 gRPC 在速度上可以比 REST+JSON 快得多,传输的数据体积更小。 2. 流 基于 HTTP/2 使得 gRPC 支持端到端的单向流传输和同时的双向流传输。 3. 代码生成 gRPC 配套的工具集,支持客户端和服务端基于 .proto 文件生成各种语言和平台的代码,使得业务端在代码编写时可以像调用函数那样进行请求的发送和响应,开发体验更加地友好。 4. 安全性 HTTP/2 是在 SSL/TLS 之上的,使得 API 的安全性有所保障。
6.2 缺点
1. 浏览器支持不友好 对于浏览器端无法直接调用 gRPC,因此如果浏览器端需要使用 gRPC,必须有一个代理层和 gRPC-web。 2. 消息可读性差 由于 gRPC 把消息转成了二进制,因此在调试分析的时候,需要使用特定的工具将消息转化成易于阅读的形式。 3**. 学习曲线陡峭** 相对于 REST+JSON 来说, gRPC 的入门学习曲线会显得陡峭一些。
7. 如何权衡是否使用 gRPC
gRPC 适用于微服务间通信,实时通信系统,低带宽通信系统。然而对浏览器不友好的特性,更多地局限于内部系统间的通信。相比来说, REST 支持所有浏览器,在兼容性上表现得更好。
8. 参考资料
What Is Remote Procedure Call (RPC)? Definition from SearchAppArchitecture
What is gRPC ❓ Concepts, Strengths and Weaknesses, Architecture