这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天
本文是对于掘金课程的课程笔记,针对课程内容的一些重难点、本人在学习RPC框架知识时候进行的简单记录。
一、本堂课的重点内容
- 基本概念
- 分层设计
- 关键指标
- 企业实践
二、详细知识点介绍
基本概念
本地函数调用 VS 远程函数调用
RPC需要解决的问题:
- 函数映射
- 数据转换成字节流(本地只需要从栈中取出参数即可)
- 网络传输
RPC概念模型:由五个部分组成,user;user-stub;rpc-runtime;server-stub;server
一次RPC的完整过程
- IDL文件:约定描述文件,通过一种中立的方式来描述接口
- 生成代码,通过编译器工具把IDL文件转换成语言对应的静态库
- 编解码
- 通信协议:规范数据在网络中的传输内容和格式
- 网络传输(TCP/UDP)
RPC的好处
- 单一职责,有利于分工协作和运维
- 可扩展性强,资源使用率更优(压力大的时候可以独立扩充资源,比如双十一压力大可以扩充资源)
- 故障隔离,可靠性高(某一个服务发生故障不会影响整体)
RPC带来的问题
- 服务宕机,对方如何处理
- 如何保证消息的可达性
- 请求量突增导致服务无法及时处理,有哪些措施
分层设计
编解码层
客户端与服务端会依赖同一份IDL文件
数据格式:
- 语言特定的格式(例如java有java.io.Serializable)
- 文本格式(json,xml,csv等,有可读性)
- 二进制编码(用的多,跨语言,高性能,thrift的binaryProtocol)
二进制编码-TLV编码
- Tag:可以理解为类型
- Length:长度
- Value:值
编码选型
- 兼容性
- 通用性
- 性能
协议层
- 特殊结束符:一个特殊字符作为每个协议单元结束的标识
- 变长协议
协议构造:
- LENGTH:数据包大小
- HEADER MAGIC:标识版本信息
- SEQUENCE NUMBER:数据包的seqID,可用于多路复用
- HEADER SIZE:头部长度
- PROTOCOL ID:编解码方式,有binary和compact两种
- TRANSFORM ID:压缩方式,有zlib和snappy
- INFO ID:传递一些定制的meta信息
- PAYLOAD:消息体
协议解析 MagicNumber -> PayLoadCodec -> Payload
网络通信层
通过Sockets AIP(介于应用层与传输层之间,传输层用TCP或者UDP)
可以使用封装好的网络库
- 提供易用API:封装底层Sockets API
- 功能:TCP UDP UDS协议支持等
- 性能:应用层BUFFER减少拷贝
关键指标
稳定性
保障策略:
- 熔断:保护调用方(A调用B,B调用C,C响应超时,B也无法响应A)
- 限流:保护被调用方(防止大流量把服务压垮)
- 超时控制:避免浪费资源在不可用节点上
提高请求成功率:
- 负载均衡(均匀调用服务的节点)
- 重试
长尾请求:使用Backup Request
如何实现这些策略?注册中间件!
易用性
- 开箱即用:合理的默认参数、丰富的文档
- 周边工具:生成代码工具,脚手架工具
扩展性
- Middleware
- Option
- 编解码层
- 协议层
- 网络传输层
- 代码生成工具插件扩展
观测性
- Log日志,Metric监控,Tracing链式跟踪
- 内置观测性服务
高性能
目标:高吞吐,低延迟
场景:
- 单机多机
- 单连接多连接
- 单/多 client
- 不同大小的请求包
- 不同请求类型
手段:
- 连接池(提高复用率)
- 多路复用(提高复用率)
- 高性能编解码协议
- 高性能网络库
企业实践
整体架构
- Kitex Core
- Kitex Byted
- Kitex Tool
自研网络库
为什么要自研网络库? 背景:
- 原生库无法感知连接状态
- 原生库存在goroutine暴涨的风险
Netpoll:
- 解决上述两个背景问题(引入epoll感知链接状态,建立goroutine池)
- 引入nocopy buffer提升性能
扩展性设计
支持多协议,也支持灵活的自定义协议扩展
性能优化
- 调度优化:epoll_wati调度控制,gopool重用goroutine降低同时运行的协程数
- LinkBuffer:读写并行无锁;nocopy buffer优化
- Pool:引入内存池和对象池,减少GC开销
编解码优化:
- Codegen:预计算并分配内存,Inline减少函数调用次数,自研 Thrift IDL解析和代码生成器
- JIT:just in time,即时编译
合并部署
问题:微服务过微,传输和序列化开销越来越大
将亲和性强的服务实例尽可能调度到同一个物理机,远程RPC调用优化为本地IPC调用
三、课后个人总结
RPC框架是非常重要的概念,本节课从本地函数调用引出RPC概念,进而介绍了RPC框架的核心三层——编解码层、协议层和网络传输层,然后介绍了RPC框架的核心指标,最后介绍了字节的高性能RPC框架Kitex,让我对RPC的相关知识有了系统性的掌握,也为我大项目的部署打下了基础。