title: RPC框架
categories: 青训营
1.基本概念
远程函数调用(RPC,Remote Procedure Calls)
RPC需要解决:
- 函数映射
- 数据转换成字节流
- 网络传输
1.1一次RPC的完整过程
- IDL (Interface description language)文件
IDL通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信
- 生成代码
通过编译器工具把IDL文件转换成语言对应的静态库
- 编解码
从内存中表示到字节序列的转换称为编码,反之为解码,也常叫做序列化和反序列化
- 通信协议
规范了数据在网络中的传输内容和格式。除必须的请求/响应数据外,通常还会包含额外的元数据
5.网络传输
通常基于成熟的网络库走 TCP/UDP传输
RPC的好处
- 单一职责,有利于分工和运维开发
- 可拓展性强
- 故障隔离,服务整体可靠性更高
RPC的问题
- 服务宕机时应如何处理
- 调用过程中发生网络异常,如何保证消息的可达性
- 请求突增无法及时处理怎么办
2.分层设计
以Apache Thrift为例
2.1编解码层
客户端和服务器依赖同一份IDL文件,生成不同语言的代码
IDL文件的数据格式有:语言特定的格式,如Java的java.io.Serializable,文本格式,如JSON,XML等,还有二进制编码格式
2.1.1 TLV编码(二进制编码)
包括字段:
- Tag: 标签,表示类型
- Lenght: 长度
- Value: 值,value也可以是一个TLV结构
Tag有时可以确定长度,就不需要Lenght字段,如Tag为int64,则长度已经是固定的
2.1.2 编码格式考量
- 兼容性:考虑兼容性问题,是否支持新增字段而不影响老的服务
- 通用性:是否跨平台,跨语言
- 性能:从时间和空间两个方面考虑
2.2协议层
协议有:
- 特殊结束符,通过一个特殊字符表示每个协议单元的结束,如HTTP以\r\n结尾
- 边长协议,以定长和不定长两部分组成,定长部分描述不定长部分的长度
2.2.1 协议构造
解析时,通过MagicNumber确定协议类别,通过PayloadCodec获取编码格式,再通过解码获取Payload
2.3网络通信层
通过Sockets API
实际应用中,使用网络库来操作,简单易用,指标有:
- 提供易用API,封装底层Socket API,连接管理和事件分发
- 功能:支持多种协议,如TCP,UDP,UDS等,可以优雅退出和具备异常处理等
- 性能:应用层buffer减少copy,高性能定时器和对象池等
3.关键指标
3.1 稳定性
- 熔断:保护调用方,防止被调用的服务影响到整个链路
- 限流:保护被调用方,防止大流量把服务压垮
- 超时控制: 避免浪费资源在不可用的节点上
使用负载均衡,使服务被均匀调用;当调用失败时,通过重试来增加请求成功率
长尾请求:响应明显高于一般请求
通过注册中间件,来控制服务的稳定性
3.2易用性
易用性要保证:
- 开箱即用:合理的默认参数,丰富的文档
- 周边工具:生产代码工具,脚手架工具等
3.3 扩展性
要尽可能提供多的扩展点,如代码生成工具支持插件拓展
3.4 观测性
内置观测性服务
三件套: Log,Metric和Tracing
3.5 高性能
目标:高吞吐,低延迟
手段:
- 连接池
- 多路复用
- 高性能编解码协议
- 高性能网络库
高性能的具体考量根据应用场景的不同而存在差异
4.企业实践
为什么要自研网络库?
原生网络库无法感知连接状态,在使用连接池时,当存在失效连接时影响连接池的复用
原生库存在goroutine暴涨的风险,影响性能