这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
课程笔记:RPC 关键指标
关键指标
稳定性
- 熔断 保护调用方,防止被调用的服务出现问题而影响到整个链路
- 限流 保护被调用方,防止大流量把服务压垮
- 超时控制 避免浪费资源在不可用节点上
请求成功率
提高成功率方式:
- 负载均衡 当有多个节点时均衡各个节点的负载
- 重试 调用失败时重试,在多次重试失败后才算真正失败
长尾请求
明显高于平均响应时间的请求
解决方式:备份请求
普通重试:
(总共需t1+t2) 备份请求:
(按以往经验平均返回时间为t3,总共需t4时间)
注册中间件
通过注册中间件,实现熔断等功能,以保证稳定性
易用性
- 开箱即用 合理的默认参数选项、丰富的文档;无需过多配置即可快速使用
- 周边工具 生成代码工具、脚手架工具
扩展性
- Middleware
- Option
- 编解码层
- 协议层
- 网络传输层
- 代码生成工具插件扩展
可观测性
- Log、Metric(监控面板)、Tracing(链路跟踪)
- 内置观测性服务
高性能
场景
- 单机多机
- 单连接多连接
- 单/多Client 单/多Server
- 不同大小请求包
- 不同请求类型,如PingPong、Streaming等
目标
- 高吞吐
- 低延迟
手段
- 连接池
- 多路复用
- 高性能编解码协议
- 高性能网络库
企业实践
整体架构
- Kitex Core 核心组件
- Kitex Byted 与公司内部基础设施集成
- Kitex Tool 代码生成工具
自研网络库
背景
- 原生库无法感知连接状态 使用连接池时,池中存在失效连接,影响连接池的复用
- 原生库存在goroutine暴涨的风险 一个连接一个goroutine的模式,由于连接利用率低下,存在大量goroutine占用调度开销,影响性能
自研网络库 Netpoll
- 解决无法感知连接状态问题 引入epoll主动监听机制,感知连接状态
- 解决goroutine暴涨的风险 建立goroutine池,复用goroutine
- 提升性能 引入 NocopyBuffer,向上提供NoCopy的调用接口,编解码层面零拷贝
扩展性设计
支持多协议,也支持灵活的自定义协议扩展
性能优化
网络库优化
- 调度优化
- epoll_wait 在调度上的控制
- gopool 重用 goroutine 降低同时运行协程数
- LinkBuffer
- 读写并行无锁,支持nocopy地流式读写
- 高效扩缩容
- NocopyBuffer池化,减少GC
- Pool
- 引入内存池和对象池,减少GC开销
编解码优化
- Codegen
- 预计算并分配内存,减少内存操作次数,包括内存分配和拷贝
- Inline减少函数调用次数和避免不必要的反射操作等
- 自研了Go语言实现的ThriftIDL 解析和代码生成器,支持完善的ThriftIDL语法和语义检查,并支持了插件机制- ThriftGo
- JIT
- 使用JIT编译技术改善用户体验的同时带来更强的编解码性能,减轻用户维护生成代码的负担
- 基于JIT编译1技术的高性能动态Thrift编解码器- Frugal
合并部署
微服务过微,传输和序列化开销越来越大
将亲和性强的服务实例尽可能调度到一个物理机,远程RPC调用优化为本地IPC调用
- 中心化的部署调度和流量控制
- 基于共享内存的通信协议
- 定制化的服务发现和连接池实现
- 定制化的服务启动和监听逻辑