RSS

gRPC Landscape

gRPC Landscape.

一、Why gRPC?

Cloud Native Interactive Landscape

CNCF 云原生景观全景图:https://landscape.cncf.io/?zoom=400

面对庞大的技术栈,有选择性的进行研究:

  • 使用上了解
  • 原理上了解
  • 设计上了解
  • 源码级了解
  • 参与贡献

Application layer

偏向 应用层 的技术栈:

messaging

mesh

rpc

serverless framework

gRPC

云原生 应用层 技术栈,大量使用了gRPC作为网络通讯的协议/框架

gRPC-go

尤其是go-sdk,在大量sidecar模式架构中进行使用。

Go语言gRPC技术栈

Why gRPC?

鉴于 gRPC 在应用层技术栈的广泛使用和重要性,对其有源码级了解是有价值的。

二、gRPC协议

设计原则

● 服务非对象、消息非引用 —— 促进微服务的系统间粗粒度消息交互设计理念,同时避免分布式对象的陷阱和分布式计算的谬误。

和 DCOM 及 EJB 完全相反的。只有数据,不包含逻辑

分布式计算谬误

  • 网络可靠;
  • 延迟为零;
  • 带宽是无限的;
  • 网络安全;
  • 拓扑不变;
  • 有一名管理员;
  • 运输成本为零;
  • 网络是同质的。

● 普遍并且简单 —— 该基础框架应该在任何流行的开发平台上适用,并且易于被个人在自己的平台上构建。它在CPU和内存有限的设备上也应该切实可行。

协议的设计应考虑全面的应用场景:边缘节点、serverless等

● 免费并且开源 —— 所有人可免费使用基本特性。以友好的许可协议开源方式发布所有交付件。

避免具体技术锁定,应是可插拔的

互通性 —— 该报文协议(Wire Protocol)必须遵循普通互联网基础框架。

同现有网络设施的兼容性和连通性

  • over HTTP
  • over TCP
  • over UDP

● 通用并且高性能 —— 该框架应该适用于绝大多数用例场景,相比针对特定用例的框架,该框架只会牺牲一点性能。

要通用性,不要极端性能优化

● 分层的 —— 该框架的关键是必须能够独立演进。对报文格式(Wire Format)的修改不应该影响应用层。

抽象的编程模型,与具体实现解耦

● 负载无关的 —— 不同的服务需要使用不同的消息类型和编码,例如protocol buffers、JSON、XML和Thrift,协议上和实现上必须满足这样的诉求。类似地,对负载压缩的诉求也因应用场景和负载类型不同而不同,协议上应该支持可插拔的压缩机制。

Payload agnostic,RPC 框架不应该规定用的是什么 payload 格式

—— 存储系统依赖于流和流控来传递大数据集。像语音转文本或股票代码等其它服务,依靠流表达时间相关的消息序列。

在某种程度上,可以将其理解为类似消息系统的消息队列。

● 阻塞式和非阻塞式 —— 支持异步和同步处理在客户端和服务端间交互的消息序列。这是在某些平台上缩放和处理流的关键。

用户态线程阻塞模型性能较差,应使用NIO编程模型,支持异步非阻塞式的交互。

取消和超时 —— 有的操作可能会用时很长,客户端运行正常时,可以通过取消操作让服务端回收资源。当任务因果链被追踪时,取消可以级联。客户端可能会被告知调用超时,此时服务就可以根据客户端的需求来调整自己的行为。

支持重置功能(RST_STREAM 帧)

Lameducking —— 服务端必须支持优雅关闭,优雅关闭时拒绝新请求,但继续处理正在运行中的请求。

优先级设计(Http2)

  • 针对流ID
  • 流级联设计

流控 —— 在客户端和服务端之间,计算能力和网络容量往往是不平衡的。流控可以更好的缓冲管理,以及保护系统免受来自异常活跃对端的拒绝服务(DOS)攻击。

维护缓冲区:窗口/背压/租约

基于HTTP2缓冲区的流控机制 基于应用层语义的流控

● 可插拔的 —— 数据传输协议(Wire Protocol)只是功能完备API基础框架的一部分。大型分布式系统需要安全、健康检查、负载均衡和故障恢复、监控、跟踪、日志等。实现上应该提供扩展点,以允许插入这些特性和默认实现。

● API扩展 —— 可能的话,在服务间协作的扩展应该最好使用接口扩展,而不是协议扩展。这种类型的扩展可以包括健康检查、服务内省、负载监测和负载均衡分配。

● 元数据交换 —— 常见的横切关注点,如认证或跟踪,依赖数据交换,但这不是服务公共接口中的一部分。部署依赖于他们将这些特性以不同速度演进到服务暴露的个别API的能力。

metadata与payload分离

● 标准化状态码 —— 客户端通常以有限的方式响应API调用返回的错误。应该限制状态代码名字空间,使得这些错误处理决定更清晰。如果需要更丰富的特定域的状态,可以使用元数据交换机制来提供。


对端平等 —— 人机交互强调 客户端->服务端 模型,机器之间交互任意一端都可作为客户端/服务端

长链接 —— 为服务端推送和双向流交互提供基础。

完善的应用层状态码命名空间

HTTP2

交互分析

  • Magic
  • SETTINGS
  • HEADERS
  • DATA
  • SETTINGS
  • WINDOW_UPDATE
  • PING
  • HEADERS
  • DATA
  • HEADERS
  • WINDOW_UPDATE
  • PING

主链路

  • Magic
  • Settings

流链路

  • Settings
  • Headers
  • data
  • Window_update

控制链路

  • Window_update
  • Ping

  • 在建立连接之前,客户端/服务端都会发送连接前言(Magic+SETTINGS),确立协议和配置项。
  • 在传输数据时,是会涉及滑动窗口(WINDOW_UPDATE)等流控策略的。
  • 传播 gRPC 附加信息时,是基于 HEADERS 帧进行传播和设置;而具体的请求/响应数据是存储的 DATA 帧中的。
  • 请求/响应结果会分为 HTTP 和 gRPC 状态响应两种类型。
  • 客户端发起 PING,服务端就会回应 PONG,反之亦可。

grpc

语义概念

gRPC 引入了三个新概念:通道、远程过程调用(RPC) 和消息。三者之间的关系很简单:每个通道可能有很多 RPC,而每个 RPC 可能有很多消息。

通道是 gRPC 中的一个关键概念。HTTP/2 中的流支持在单个连接上进行多个并发会话;通道通过在多个并发连接上启用多个流来扩展这个概念。

通道代表到端点的虚拟连接,实际上可能由许多 HTTP/2 连接支持。RPC 与连接相关联。RPC 实际上是普通的 HTTP/2 流。消息与 RPC 相关联并作为 HTTP/2 数据帧发送。更具体地说,消息是在数据帧之上分层的。一个数据帧可能有很多 gRPC 消息,或者如果一个 gRPC 消息非常大它可能跨越多个数据帧。

gRPC 对 16kb 的数据帧使用 HTTP/2 默认的最大大小。超过 16kb 的消息可能跨越多个数据帧,而低于该大小的消息可能与一些其他消息共享一个数据帧。

并非与HTTP2强绑定?

  • Channel
    • Conns
    • 负载均衡
  • RPC
    • Conn
    • Stream
  • Message
    • Frame m:n

三、gRPC框架

主链路

  • 启动net server *
  • Stub
    • Contact
      • proto
    • Channel
      • 生命周期
    • 业务executor
  • Channel
    • 创建ClientCall(RPC)
    • 将ClientCall转化成realCall(H2 Conn)
    • 将realCall转化成realStream (H2 Stream)
    • 执行realStream
    • 获取Response

H2 Conn:

startCall

call.sendMessage

call.halfMessage

TODO

https://juejin.cn/post/6844903984524705800 https://grpc.io/docs/what-is-grpc/core-concepts/ https://grpc.io/blog/grpc-on-http2/ https://grpc.io/blog/yikyak/ https://grpc.io/blog/grpc-load-balancing/ https://segmentfault.com/a/1190000019608421