RPC原理与实现 | 青训营笔记

91 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 14 天

RPC框架

基本概念

本地函数调用

func main(){
    var a = 2
    var b = 3
    result := calculate(a, b)
    print(result)
}
func calculate(var x, var y){
    return x + y
}

远程函数调用(RPC)

相较于本地函数调用,中间隔了一层网络,需要解决函数映射数据转换成字节流网络传输等问题

IDL文件:IDL通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编程的程序可以相互沟通

生成代码:通过编译器将IDL文件转换成语言对应的静态库

编解码:从内存中表示到字节序列的转换称为编码,反之为解码,也常叫做序列化和反序列化

通信协议:规范了数据在网络中的传输内容和格式,除必须的请求和响应数据外,通常还会包括额外的元数据

网络传输:通常基于成熟的网络库走TCP/UDP传输

优势

单一职责,有利于分工协作和运维开发、可扩展性强,资源使用率高、故障隔离,服务的整体可靠性更高

分层设计

编解码层

一般数据格式:语言特定的格式、文本格式(人类可读性)、二进制编码(跨语言、高性能)

TLV编码:T标签、L长度、V值

编码格式选择标准:兼容性(系统灵活性)、通用性(支持跨平台、跨语言)、性能(空间和时间维度)

协议层

特殊结束符:一个特殊字符作为每个协议单元结束的标示

变长协议:以定长加不定长的部分组成,定长部分需要不定长的内容长度

协议解析:读取顺序:MagicNumber(获取协议的类型)->PayloadCodec(获取解码方式)->Payload(消息主体)

网络通信层

介于应用层和传输层(TCP/UDP)之间,之后是网络层(IP)和物理层

一般使用封装好的网络库作为RPC框架的网络通信层

网络库核心指标:提供易用API(封装底层socket api、连接管理和事件分发)、功能(协议支持、优雅退出、异常处理等)、性能(应用层buffer减少copy、高性能定时器、对象池等)

关键指标

稳定性

保障策略:熔断(保护调用端)、限流(保护被调用端)、超时控制(避免资源浪费)

请求成功率:负载均衡、重试

长尾请求:Backup Request(备份请求,设定时间内未收到返回则再次请求)

注册中间件:将以上的策略或功能灵活注入

易用性

开箱即用(合理的默认参数、丰富的文档)、周边工具(生成代码工具、脚手架工具)

扩展性

扩展点:Middleware(中间件)、Option、编解码层、协议层、网络传输层、代码生成工具插件扩展

观测性

Log(日志)、Metric(监控)、Tracing(链路跟踪)

内置观测性服务

高性能

目标:高吞吐、低延迟

手段:连接池、多路复用、高性能编解码协议、高性能网络库

企业实践

Kitex

整体架构:Kitex Core、Kitex Byted、Kitex Tool

自研网络库Netpoll

go原生的库存在缺陷

自研库解决了无法感知连接状态问题(引入epoll主动监听机制)、解决goroutine暴涨的风险(建立goroutine池,复用goroutine)、提升性能(引入Nocopy Buffer,编解码层零拷贝)

支持多协议

交互方式:Ping-Pong、Streaming、Oneway

编解码:Thrift、Protobuf

应用层:TTHeader、HTTP2

传输层:TCP

性能优化

网络库优化--调度优化、LinkBuffer、Pool

编解码优化--CodeGen、JIT