深入浅出RPC框架
一、基本概念
-
RPC需要解决的问题
函数映射
数据转换成字节流
网络传输
-
RPC概念模型
RPC的过程由5个模型组成:User、User-Stub、RPC-Runtime、Server-Stub、Server
3·一次RPC的完整过程
IDL文件->生成代码->编解码->通信协议->网络传输
4·RPC的好处
单一职责
可拓展性强,资源使用更优
故障隔离,服务的整体可靠性更高
5·RPC带来的问题
服务宕机,对方如何处理
在调用过程中发生网络异常,如何保证消息的可达性
请求量突增导致服务无法及时处理,有哪些应对措施
解决方案:使用RPC框架
二、分层设计
-
编解码层
生成代码:Client和Server依赖同一份IDL文件,生成不同语言的CodeGen(Goland、C++、Java)
数据格式
语言特定的格式:许多编程语言都内建了将内存对象编码为字节序列的支持,eg:Java有java.io.Serializable
文本格式:JSON、XML、CSV等文本格式,具有人类可读性
二进制编码:具备跨语言和高性能等优点,常见有Thrift的BinaryProtocol、Protobuf等
二进制编码中的TLV编码:
Tag:标签,可以理解为类型
Lengtht:长度
Value:值,Value也可以是个TLV结
-
协议层
概念
特殊结束符:一个特殊字符作为每个协议单元结束的标示
变长协议:以定长加不定长的部分组成,其中定长的部分需要描述不定长的内容长度
协议解析
Peek->MagicNumber->Peek->PayloadCodec->Decode->Payload
三、关键指标
-
稳定性
保障策略
熔断、限流、超时控制:避免浪费资源在不可用节点上
请求成功率
负载均衡
重试
长尾请求
注册中间件
-
易用性
开箱即用:合理的默认参数选项,丰富的文档
周边工具:生成代码工具、脚手架工具
简单易用的命名行工具:生成服务代码脚手架、支持protobuf和thrift、内置功能丰富的选项、支持自定义的生成代码插件
-
拓展性
Middleware
Option
编解码层
协议层
网络传输层
代码生成工具插件拓展
-
观测性
Log、Metric、Tracing
内置观测性服务
-
高性能
场景
单机多机
单连接多连接
单/多client 单/多server
不同大小的请求包
不同请求类型:例如pingpong、streaming等
目标:高吞吐、低延迟
手段:连接池、多路复用、高性能编解码协议、高性能网络库
四、企业实践
-
整体架构
Kitex(核心组件)、Kitex byted(与公司内部基础设施集成)、Kitex Tool(代码生成工具)
-
自研网络库
原生库无法感知连接状态:在使用连接池时,池中存在失效连接,影响连接池的复用
原生库存在goroutine暴涨的风险:一个连接一个goroutine的模式,由于连接利用率低下,存在大量goroutine占用调度开销,影响性能
-
拓展性设计
支持多协议,也支持灵活的自定义协议拓展
-
性能优化
网络库优化
编解码优化
-
合并部署
微服务过微,传输和序列化开销越来越大
将亲和性强地服务实例尽可能调度到同一个物理机,远程RPC调用优化为本地IPC调用
中心化的部署调度和流量控制
基于共享内存的通信协议
定制化的服务发现和连接池实现
定制化的服务启动和监听逻辑