gRPC设计动机和原则

https://mp.weixin.qq.com/s/NMIIa0W722zo_AxCqASc0g

TiDB 与 gRPC 的那点事儿

黄东旭 PingCAP 2017-08-10
 

gRPC 背景介绍

其实做分布式系统那么久,几乎也是天天和 RPC 打交道,要说 各个模块是系统的筋肉,那 RPC 就是整个系统的血管,数据的流通,信令的传递,都离不开 RPC。

RPC 并不是一个固定的东西,可重可轻,重的如同 MS 的 DCOM,JAVA 的 EJB,轻的 HTTP 也可以说是 RPC,甚至自己写个 TCP 的文本通信协议也算。

大家也都知道 Google 内部其实没怎么用 gRPC,大量使用的是 Stubby,它作为 gRPC 的前身,也是一个 Protobuf RPC 的实现,因为大量依赖了 Google 的其他基础服务所以不太方便开放出来给社区使用。

随着 SPDY / QUIC,乃至 HTTP/2  的成熟,Google 决定用这些更加标准的组件来构建一个新的 RPC 框架,也就是 gRPC。不过这个项目过于庞大,而且 Google 内部 Stubby 已经用了超过 10 年,很难直接替换,毕竟程序员最烦的事情之一就是去改跑着好好的老代码。。。

不过 anyway,尽管 gRPC 没有在 Google 内部广泛使用,也是给社区带来了一个非常好的基础组件,现在为止包括 ETCD / Kubernetes / TiDB 在内的大量社区顶级开源分布式项目都在使用它。

为何选择 gRPC?

有人说,RPC 多简单啊,不就是一个长连接,Sender 和 Reciver 来回发包嘛,顶多再搞个服务发现做 Failover,搞得那么复杂为啥。另外要强大不是已经有 EJB 什么的嘛,gRPC 的意义何在?我想从官方的 gRPC 的设计动机和原则说起:

1、Google 应该是践行服务化的先驱之一,在业界没那么推崇微服务的时代,Google 就已经大规模的微服务化。

微服务的精髓之一就是服务之间传递的是可序列化消息,而不是对象和引用,这个思想是和 DCOM 及 EJB 完全相反的。只有数据,不包含逻辑;这个设计的好处不用我多说也很好理解,参考 CSP 。

2、Protobuf 作为一个良好的序列化方案,注意,只是 序列化(尽管 pb 也有定义 rpc service 的能力,Protobuf 默认生成的代码并不包含 RPC 的实现),它并不像 Thrift 天生就带一个 RPC Framework,相对的来说比较轻。

在 gRPC 的设计中,一个很重要的原则就是 Payload agnostic,RPC 框架不应该规定用的是什么 payload 格式,可以是 Protobuf,JSON,XML,这也让 gRPC 的设计和层次更加清晰。

3、比传统的 Request / Response 更丰富的 API Interface,这个是我们使用 gRPC 的重要理由,gRPC 不仅支持传统的一应一答的模式,更是支持三种 Streaming 的调用方式,现代的业务经常会需要传输大的数据流,Streaming API 的设计让这些业务写起来轻松很多。

4、有了 Streaming 就不可避免地需要引入 Flow-control ,这点 gRPC 的处理很聪明,直接依赖了 HTTP/2,在流控这边不怎么用操心,顺带还可以用 HTTP 反向代理做负载均衡。

但是另一方面也会带来更多的调优复杂度,毕竟和 Web 的使用场景不太一样,比如默认的 INITIAL_WINDOW_SIZE 在 gRPC 里是 64k,太小,吞吐上不去,需要人工改大。

5、另一方面由于直接使用了 HTTP/2,TLS 的支持就几乎是天然的,对于 TiDB 这样的商业数据库而言,传输层加密是一个很重要的功能,在 gRPC 中直接就可以支持。本着不重新造轮子的原则,直接用 gRPC 就好了。

https://mp.weixin.qq.com/s/nH4WG1lY56LvXATh_cvPVw

深度解析gRPC以及京东分布式服务框架跨语言实战

闫家宝 亿级流量网站架构 2017-02-22

gRPC设计动机和原则

最初由Louis Ryan在谷歌其他同事帮助下写成,如下文:

设计动机

十多年来,谷歌一直使用一个叫做Stubby的通用RPC基础框架,用它来连接在其数据中心内和跨数据中心运行的大量微服务。其内部系统早就接受了如今越来越流行的微服务架构。拥有一个统一的、跨平台的RPC的基础框架,使得服务的首次发行在效率、安全性、可靠性和行为分析上得到全面提升,这是支撑这一时期谷歌快速增长的关键。

Stubby有许多非常棒的特性,然而,它没有基于任何标准,而且与其内部的基础框架耦合得太紧密以至于被认为不适合公开发布。随着SPDY、HTTP/2和QUIC的到来,许多类似特性在公共标准中出现,并提供了Stubby不支持的其它功能。很明显,是时候利用这些标准来重写Stubby,并将其适用性扩展到移动、物联网和云场景。

设计原则

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

原文地址:https://www.cnblogs.com/rsapaper/p/13613927.html