gRPC 概要笔记
gRPC 概要笔记,包含序列化、protobuf、http/2、服务发现、负载均衡、流控。
gRPC
gRPC (Google Remote Procedure Call) 是由 Google 于 2015 年开源的高性能、通用的 RPC 框架。 其出现的背景是微服务通信激增、及跨语言通信等。[1]
序列化与反序列化
涉及 RPC,就必须依赖序列化与反序列化,以便在网络和各个服务中传递对象、数据交换等。
跨语言的序列化有如下几种:protobuf、thrift、hessian 等,gPRC 的默认序列化方案是 protobuf。
与 JSON 序列化或 Java 原生序列化相比,protobuf 有如下优势:
| 特性 | Protobuf | JSON | Java 原生序列化 |
|---|---|---|---|
| 数据格式 | 二进制(紧凑) | 文本(冗余) | 二进制(极度冗余) |
| 可读性 | 不可读(需工具还原) | 可读 | 不可读 |
| 生成体积 | 极小 | 一般 | 极大 |
| 解析速度 | 极快 | 一般 | 慢 |
| 语言支持 | 主流多语言支持 | 几乎任何语言 | 仅限 Java |
| Schema 约束 | 强类型(编译期检查) | 弱类型 | 强类型(耦合高) |
Java 序列化框架(Hession、Fastjson、Jackson、Gson)普遍存在反序列化漏洞,而 protobuf 通过限定类和显示调用,不存在此问题。[2]
protobuf
protobuf 是 gRPC 的默认序列化方案,但也是可选的。通过序列化与反序列化的对比,可以看到 protobuf 主要解决跨语言通信问题、类型统一且为强类型、二进制、体积及高效传输。
HTTP/2
gRPC 的应用层协议为 HTTP/2,利用了 HTTP/2 的较多新特性,包括:
- 支持二进制分帧传输
- 长连接,且多路复用,单个请求可处理多个请求和响应
- 可通过流(Stream)和帧(Frame)实现并行传输
- 支持流式双向通信
服务发现与负载均衡
gRPC 有较为简单的服务发现机制,内部默认通过 DNS 来做服务发现 [3],但由于 DNS 的 TTL 缓存机制,服务发现并没有那么及时,所以可以配合 xDS 等方案,配合 Envovy / Istio 等支持更为实时的服务发现。[5][6]
复杂均衡,是在服务发现后,如何选择具体哪台服务器进行调用,默认为 pick_first 策略,即选择第一个可用服务 [7]。也可自定义相关的负载均衡策略。
流量控制
这块是最为主要的实现逻辑,包括:认证机制、数据压缩、取消机制、超时机制、排队机制、健康检查、重试等。
一次简单请求的大致流程如下:
- resolving_load_balancer 解析服务也有复杂均衡
- dns_resolver DNS 解析器
- resolving_call 解析操作
- pick_first 选择第一个可用服务
- resolving_call 解析操作
- dns_resolver DNS 解析器
- channel 建立服务连接
- subchannel 多路复用
- retrying_call 叠加重试机制
- subchannel_call 单个调用
- retrying_call 叠加重试机制
- subchannel 多路复用
- transport 传输层
- transport_internals 内部处理,包括保活、连接、代理等
以上步骤可通过官方样例查看 [8]
git clone --depth 1 --shallow-submodules https://github.com/grpc/grpc-nodecd grpc-node/examplesnpm installcd helloworld/dynamic_codegennode greeter_server.js开启服务GRPC_NODE_VERBOSITY=DEBUG GRPC_NODE_TRACE=all node greeter_client.js通过环境变量开启整体流程的观察