REST (or JSON over HTTP 1.1)
广义来说当然也算是RPC, 不过现在”RPC”貌似都是特指使用二进制协议的轮子
优点:
- 简单, 可以用 curl / 浏览器等工具调试
- 生态圈丰富
- 和后台开发可以复用一套API接口 (例如网盟中间层和网盟后台, 广告查询接口)
- 广泛可选的基于HTTP的基础组件服务, 如Caching, Load Balance, …
缺点:
- HTTP 请求的 Header 字段 overhead 较高, 请求参数解析开销较高, JSON 格式序列化开销很高; 因此在某些追求性能的场合, 使用二进制的协议更加高效
设计检查工具:
JSON-RPC
--> { "method": "echo", "params": ["Hello JSON-RPC"], "id": 1}
<-- { "result": "Hello JSON-RPC", "error": null, "id": 1}
- 不一定需要依赖于 HTTP, 一问一答方式通讯
- JSON-RPC 2.0 功能更加丰富
- src/net/rpc/jsonrpc: Go标准库自带实现
- 问题还是JSON格式, 解析开销太大, 另外请求及返回参数的overhead较高
Redis Protocol
了解到公司内部也在使用, 好处是通讯协议异常简单, 也是基于文本的协议.
- 可以使用nc, redis-cli等工具调试
- 可以很好的复用已有的 Client library
- 适合于基于redis查询的业务逻辑迁移, 或者是redis数据读写不能满足需求时的KV数据库重构
- 表达复杂的数据结构还是比较蛋疼
gRPC
源于Google的内部RPC框架, 使用protobuf进行编码解码.
优点:
- 使用 Protocol Buffer 序列化高效, 生成数据小
- 比 Thrift 强
- 支持 JSON 结构映射
- 传输协议基于HTTP/2
- 可以共享基于HTTP/2的各种基础服务/组件, 前景广阔
- multiplexing over single TCP conn, 慢请求不会影响快速响应的调用
- (bidirectional) streaming rpc support
- 适合作为CS交互协议, 比如以后和SDK通讯啥的
- Google 背书, 主导开发, 文档维护啥的好些
- 一个爸爸, Go生态圈比较完善
- http://github.com/grpc-ecosystem/go-grpc-middleware
- 支持 OpenTracing
- context / tracing / …
- 有现成翻译 REST API 的项目可用, 便于DEBUG和其他Client的调用
- etcd 等明星项目背书
Thrift
- 目前看来, 性能似乎明显好于 gRPC
- 私有传输协议
- Facebook 贡献的开源项目, 现在不玩了 (FB家开源维护不够, 自己又另起炉灶了), 缺少主导, 推力有限, 文档不好
- Apache 系等项目普遍采用 Hadoop / Storm / HBase / Parquet 见这里
Thrift vs gRPC
- 实际体验来讲, 感觉和 Thrift 相比, gRPC 对于 Go 更加完善, API更加简洁, 文档帮助更加完善
- gRPC 使用 HTTP2, 前景更好
- gRPC 对于 Thrift 的性能劣势, 主要在于 HTTP2 的 Header overhead. 不过这一部分对于 统一的 鉴权, 缓存等的处理, 还是值得的
- gRPC CNCF 钦点
- … 编不下去了, 就是主观看不上 Thrift, 你看那官网丑的
Avro RPC
调研Avro格式原因: Avro格式在Hadoop以及AWS大数据的生态圈里面. 考虑”不远的”将来ETL过程日志计划统一用Avro格式存储. Avro也有RPC支持, 虽然日志序列化和RPC没啥关系, 但是如果能够用一套序列化方案是不是更加简单一些.
题外话: 日志/数据最终列式存储, 落地到S3 / HDFS, 一般采用 Parquet 格式, 从 Avro / Thrift / Protobuf 格式生成 Parquet 文件的便利性需要调研. (Avro => Parquet , 由于都是Apache系列, 支持是没有问题的)
优点: 预编译是一个可选项, 一个JSON描述的数据结构. 更加适合动态语言.
缺点:
- 由于每次通讯需要预先沟通格式, 作为RPC来说overhead太高, 还是适合以自解释的数据文件存储方式
- Go / PHP 不在官方优先支持之列
- goavro 项目
- 缺少对于RPC的支持
- 缺少对于struct格式的支持, 不方便, 这个 star 太少, 不敢用
TChannel
优点:
- 同时支持 HTTP+JSON 和 Thrift, 易用性/性能得兼
缺点:
- 非主流
- 目前不支持PHP
Go 自带的 RPC
- 性能不错
- gob 序列化方式, 无法跨语言, 放弃
Go端开发考量
- go-kit 比较成熟的Go微服务开发框架
- HTTP, gRPC, thrift, net/RPC 都支持
PHP端调用的考量
- 追求性能得上 swoole, 类似 NodeJS 事件回调的写法
- 2.0 支持类似goroutine的Coroutine, 用同步代码实现异步程序
- Redis Protocol 简单, 另外client library成熟, overhead 比 JSON over HTTP 强, 但是数据结构支持是硬伤, 请求/返回内容不好规范化
- Thrift / gRPC PHP client 可能会踩坑, 需要进一步调研
- Thrift 序列化慢, 得上专门的扩展
- 据说 Thrift PHP client 有坑, 得自己改
- 据说 gRPC 的 PHP 扩展有内存泄露问题
- 如果考虑 gRPC, PHP 对于 HTTP2 支持成熟度需要调研
- 更简单鲁棒的办法: 自己写个简单的二进制协议, 用 Protocol Buffer 做数据格式
- 以后PHP整体迁移掉后协议不用怎么改
Reference
- gRPC 相关
- Thrift 相关
- RPC 间的比较
- 序列化方式的比较