这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天
基本概念
远程函数调用(RPC - Remote Procedure Calls)
RPC解决的问题:
函数映射:在本地调用中,函数体是直接通过函数指针来指定的,我们调用哪个方法,编译器就自动帮我们调用它相应的函数指针。在远程调用中,函数指针是不行的,因为两个进程的地址空间是完全不一样的,所以函数都有自己的一个ID,在做RPC的时候需要附上这个ID,通过ID找到对应的函数并执行。
数据转换为字节流:客户端将参数转换为字节流传给服务端,服务端再把字节流转换成自己能读取的格式
网络传输:
RPC 概念模型
1984年 Nelson 提出了RPC的过程由5个模型组成:User、User-Stub、RPC-Runtime、Server-Stub、Server
一次RPC的完整过程
-
IDL(Interface Description Language)文件
IDL 通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以互相通信
-
生成代码
通过编译器工具把IDL文件转换为语言对应的静态库
-
编解码
从内存中表示到字节序列的转换成为编码,反之为解码,也叫做序列化和反序列化
-
通信协议
规范了数据在网络中的传输内容和格式。除必须的请求/相应数据外,通常还会包含额外的元数据
-
网络传输
通常基于成熟的网络库走TCP/UDP传输
RPC好处
- 单一职责,有利于分工协作和运维开发,开发、部署以及运维都是独立的
- 可扩展性强,资源利用更优,例如压力过大可以独立扩充资源,底层基础服务可以复用,节省资源
- 故障隔离,服务的整体可靠性更高,某个模块发生故障,不会影响整体的可靠性
RPC问题
- 服务宕机
- 在调用过程中发生网络异常
- 请求量突增导致服务无法及时处理
RPC框架
分层设计
以Apache Thrift为例
编解码层
数据格式
- 语言特定的格式:可以用很少的额外代码实现内存对象的保存与恢复
- 文本格式:文本格式具有人类可读性,但是数字的编码多有歧义之处,如XML和CSV不能区分数字和字符串,JSON可以区分字符串和数字,但是不区分整数和浮点数,而且不能指定精度
- 二进制编码:具备跨语言和高性能等优点,常见的有Thrift的BinaryProtocol,Protobuf等
二进制编码
TLV编码:
- Tag:标签,可以理解为类型
- Length:长度
- Value:值,Value也可以是个TLV结构
协议层
特殊结束符:一个特殊字符作为每个协议单元结束的标识
变长协议:以定长加不定长的部分组成,其中定长的部分需要描述不定长的内容字节长度
网络通信层
网络库
-
提供易用API
- 封装底层Socket API
- 连接管理和事件分发
-
功能
- 协议支持:tcp、udp和uds等
- 优雅退出、异常处理等
-
性能
- 应用层buffer减少copy
- 高性能定时器、对象池等
关键指标
稳定性
保障策略
- 熔断:保护调用方,防止被调用的服务出现问题而影响到整个链路
- 限流:保护被调用方:防止大流量把服务压垮
- 超时控制:避免浪费资源在不可用的节点上
请求成功率:负载均衡和重试
长尾请求
注册中间件
易用性
扩展性
- Middleware
- Option
- 编解码层
- 协议层
- 网络传输层
- 代码生成工具插件扩展
观测性
log:打日志 metric:监控面板参数 Tracing:串起整个链路
高性能
小结
- 框架通过中间件来注入各种服务治理策略,保障服务的稳定性
- 通过提供合理的默认配置和方便的命令行工具可以提升框架的易用性
- 框架应当提供丰富的扩展点,例如核心的传输层和协议层
- 观测性除了传统的log、Metric和Tracing之外,内置状态暴露服务也很有必要
- 性能可以从多个层面去优化,例如选择高性能的编解码协议和网络库