这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天
RPC 即 Remote Procedure Calls远程过程调用;
它与本地过程调用相对;
远程函数调用:
RPC需要解决的问题是: 函数映射; 数据转换成字节流; 网络传输
在本地调用中,函数体是直接通过函数指针来指定的,我们调用哪个方法,编译器就自动帮我们调用它相应的函数指针;
在做RPC的时候就要附上函数本身的ID,以及ID和函数的对照关系表,以便通过ID找到对应的函数并执行。
RPC的好处:
- 单一职责,有利于分工协作和运维开发;
- 可扩展性强,资源使用率更优;
- 故障远离,服务的整体可靠性更高;
RPC带来的问题:
- 服务宕机,对方应该如何处理?
- 在调用过程中发生网络异常,如何保证消息的可达性?
- 请求量突增导致服务无法及时处理,有哪些应对措施?RPC框架
分层设计
编解码层:
Client和Server都依赖同一份IDL文件,生成不同语言的CodeGen;
编解码层的选型考量:
- 兼容性:支持自动增加新的字段,而不影响老的服务,这可以提高系统的灵活度
- 通用性:支持跨平台、跨语言
- 性能:从时间空间两个维度考虑
协议层:
协议解析:
网络通信层:
Sockets API:
套接字编程中,客户端必须知道两个信息:
- 服务器的IP地址
- 端口号
网络库:
-
提供易用API
- 封装底层Socket API
- 连接管理和事件分发
-
功能
- 协议支持:TCP UDP UDS...
- 优雅退出、异常处理...
-
性能
- 应用层buffer减少copy
- 高性能定时器、对象池...
关键指标
稳定性
保障策略:
- 熔断:保护调用方,防止被调用的服务出现问题而影响到整个链路
- 限流:保护被调用方,防止大流量把服务压垮
- 超时控制:避免浪费资源在不可用节点上
请求成功率:
易用性
- 开箱即用:合理的默认参数选项 + 丰富的文档
- 周边工具:生成代码工具 + 脚手架工具
扩展性
- Middleware
- Option
- 编解码层
- 协议层
- 网络传输层
- 代码生成工具插件扩展
观测性
- Log、Metric、Tracing
- 内置观测性服务
高性能
自研网络库-Netpoll
背景:
- 原生库无法感知连接状态:在使用连接池时,池中存在失效连接,影响连接池的复用;
- 原生库存在goroutine暴涨的风险:一个连接一个goroutine的模式,由于连接利用率低下,存在大量goroutine占用调度开销,影响性能;
Netpoll:
- 解决无法感知连接状态问题:引入epoll主动监听机制,感知连接状态;
- 建立goroutine池,复用goroutine;
- 引入Nocopy Buffer,向上提供NoCopy的调用接口,编解码层面零拷贝;
扩展性设计
性能优化
- 调度优化
- LinkBuffer
- Pool
- CodeGen
- JIT