这是我参与「第三届青训营-后端场」笔记创作活动的的第12篇笔记。
基本概念
相比本地函数调用,RPC调用需要解决的问题
- 函数映射
- 数据转换成字节流
- 网络传输
一次 RPC 的完整过程
- IDL(interface description language) 文件:IDL 通过一种中立的方式描述接口,使得不同平台上运行的对象和用不同语言编写的程序可以相互通信。
- 生成代码:通过编译工具把 IDL 文件转换成对应的静态库
- 编解码:从内存中表示到字节序列的转换称为编码,反之为解码,也称为序列化和反序列化
- 通信协议:规范了数据在网络中的传输内容和格式。除了必须的请求/响应数据外,通常还会包含额外的元数据
- 网络传输:通常基于成熟的网络库走TCP/UDP传输
RPC 的好处:服务分工
- 单一职责,有利于分工协作和运维开发
- 可扩展性强,资源使用率更优
- 故障隔离,服务的整体可靠性更高
RPC 带来的问题:将由 RPC 框架来解决
- 服务宕机如何感知?
- 遇到网络异常应该如何应对?
- 请求量暴增怎么处理?
RPC 框架分层设计
编解码层
数据格式比较:
- 语言特定格式:编程语言内建支持,如 Java 的 java.io.Serializable
- 文本格式:JSON、XML、CSV 等文本格式,具有人类可读性
- 二进制编码:跨语言、高性能,如 Thrift 的 BinaryProtocol,Protobuf 等
Thrift BinaryProtocol 采用的 TLV 编码
- Tag:标签,可以理解为类型
- Length
- Value:值,也可以是 TLV 结构
协议层
特殊结束符:使用特殊字符作为每个协议单元结束的标识
| message body | \r\n | message body | \r\n |
|---|
变长协议:以定长的部分描述不定长内容长度
| length | message body | length | message body |
|---|
网络通信层
提供易用API
- 封装低层 Socket API
- 连接管理和事件分发
功能
- 协议支持:TCP, UDP, UDS等
- 优雅推出、异常处理
性能
- 应用层 buffer 减少 copy
- 高性能定时器、对象池等
RPC 框架核心指标
稳定性
降级措施
- 熔断:保护调用方,防止由于被调用服务出现问题影响整个链路
- 限流:保护被调用方,防止大流量把服务压垮
- 超时控制
提高请求成功率
- 负载均衡
- 重试
处理长尾请求
- Backup Request
框架通过注册中间件实现上述的措施。
易用性
- 开箱即用
- 合理的默认参数选项、丰富的文档
- 周边工具
- 生成代码工具、脚手架工具
扩展性
- Middleware:middleware 会被构造成一个有序调用链逐个执行,比如服务发现、路由、负载均衡、超时控制等
- Option:作为初始化参数
- 核心层是支持扩展的:编解码、协议、网络传输层
- 代码生成工具也支持插件扩展
观测性
- Log, Metric, Tracing
- 框架内置观测性服务
高性能
高吞吐、低延迟
- 连接池和多路复用:复用连接,减少频繁建联带来的开销
- 高性能编解码协议:Thrift、Protobuf、Flatbuffer 和 Cap'n Proto 等
- 高性能网络库:Netpoll 和 Netty 等