深入浅出RPC框架 | 青训营笔记

71 阅读6分钟

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

本节课由浅入深地讲解一些框架的内部原理,主要讲解RPC框架

1、基本概念

1.1 本地函数调用

1.2 远程函数调用(RPC-Remote Procedure Calls)

RPC亟待解决的问题:函数映射、数据转换字节流、网络传输

RPC中函数指针是不行的,因为两个进程的地址空间是完全不一样的,函数都有自己的一个ID,在做RPC时要附上该ID,还需要有个ID和函数的对照关系表,通过ID找到对应的函数并执行

客户端跟服务端是不同的进程,不能通过内存来传递参数,需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成能读取的格式

1.3 RPC概念模型

User、User-Stub、RPC-Runtime、Server-Stub、Server

1.4 一次RPC的完整过程

IDL(Interface Description Language):描述接口,声明方法及方法的参数,使得不同平台对象和不同编程语言程序可以相互通信

生成代码:服务双方通过约定规范进行RPC,都依赖同一份IDL文件,需要通过编译工具把IDL文件转换成语言对应的静态库

编解码:编码、解码

通信协议

网络传输:TCP/UDP

1.5 RPC优点

(1)单一职责,采用不同语言开发、部署及上线运维都是独立的

(2)可扩展性强,例如压力过大可以独立扩充资源,底层基础服务可以复用,节省资源

(3)故障隔离,服务整体可靠性更高

1.6 RPC问题

(1)服务器宕机

(2)调用过程中网络异常

(3)请求量突增导致服务无法及时处理

2、分层设计-以Apache Thrift为例

自顶向下:业务逻辑代码->把IDL文件转换成不同语言对应的Lib代码->框架的编解码层->框架的协议层->框架的网络通信层

2.1 编解码层

2.1.1 生成代码

2.1.2 数据格式

语言特定的格式:例如Java的java.io.Serializable。编码非常方便,可以用很少的额外代码实现内存对象的保存与恢复,与特定的编程语言深度绑定,其他语言难以读取

文本格式:具有人类可读性,数字编码多有歧义

二进制编码:跨语言、高性能,如TLV编码和Varint编码

2.1.2.1 二进制编码

TLV编码:结构简单清晰,扩展性较好,增加了Type和Length两个冗余信息,会有额外的内存开销

2.1.3 选型

兼容性:支持自动增加新的字段,不影响老服务

通用性:跨平台、跨语言。技术层面,序列化协议是否支持跨平台、跨语言,如不支持,在技术层面上的通用性大大降低;流行程度,序列化和反序列化需要多方参与,流行度低的协议往往缺乏稳定而成熟的跨语言、跨平台的公共包

性能:空间开销(Verbosity),序列化需要在原有数据上加上描述字段;时间开销(Complexity),较长的解析时间可能会使得序列化和反序列化阶段成为整个系统的瓶颈

2.2 协议层

2.2.1 概念

特殊结束符:一个特殊字符作为每个协议单元结束的标示,过于简单,对于一个协议单元必须要全部读入才能够全部处理,必须要防止用户传输的数据不能以同结束符相同

变长协议:自定义协议,由header和payload组成,会以定长加不定长的部分组成,其中定长的部分需要描述不定长的内容长度,使用广泛

2.2.2 协议改造

LENGTH、HEADER MAGIC、SEQUENCE NUMBER、HEADER SIZE、PROTOCOL ID、TRANSFORM ID、INFO ID、PAYLOAD

2.2.3 协议解析

2.3 网络通信层

2.3.1 Sockets API

2.3.2 网络库

提供易用API:封装底层Socket API,连接管理和事件分发

功能:支持TCP、UDP和UDS等协议,优雅退出、异常处理等

性能:应用层buffer减少copy,高性能定时器、对象池等

3、关键指标

3.1 稳定性

3.1.1 保障策略

熔断:保护调用方,防止被调用的服务出现问题影响到整个链路

限流:保护被调用方,防止大流量把服务压垮

超时控制:避免浪费资源在不可用节点上

3.1.2 请求成功率

防止重试风暴,限制单点重试和限制链路重试

3.1.3 长尾请求

指明显高于均值的那部分占比较小的请求

3.1.4 注册中间件

Kitex Client和Server的创建接口均采用Option模式,提供了极大的灵活性

3.2 易用性

开箱即用:合理的默认参数选项、丰富的文档

周边工具:生成代码工具、脚手架工具

Kitex使用Suite来打包自定义的功能,提供“一键配置基础依赖“的体验

3.3 扩展性

3.4 观测性

传统的Log、Metric、Tracing,还有当前环境变量、配置、Client/Server初始化参数、缓存信息

3.5 高性能

高吞吐和低延迟

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

4、企业实践

Kitex是一个高性能高可扩展性的go RPC框架

4.1 整体框架-Kitex

核心组件Kitex Core;kitex Byted与公司内部基础设施集成,Byte部分是在生成代码中初始化Client和Server时通过Suite集成进来;Kitex Tool代码生成工具

4.2 自研网络库

原生库无法感知连接状态;原生库存在goroutine暴涨的风险

4.2.1 Netpoll

解决无法感知连接状态问题,引入epoll主动监听机制;解决goroutine暴涨的风险;提升性能,引入Nocopy Buffer,向上层提供Nocopy调用接口,编解码层面零拷贝

4.3 扩展性设计

支持多协议,支持灵活的自定义协议扩展,交互方式支持ping-pong、streaming、oneway

编解码支持Thrift、Protobuf

应用层协议支持TTHeader、Http2、裸Thrift协议

传输层支持TCP

4.4 性能优化

4.4.1 网络库优化

调度优化;LinkBuffer;Pool

4.4.2 编解码优化

Codegen优点是库开发者实现相对简单,缺点是增加业务代码的维护成本和局限性;JIT(just-in-time complication),当某段代码即将第一次被执行时编译

4.5 合并部署

将亲和性强的服务实例尽可能调度到同一个物理机,远程RPC调用优化为本地IPC调用

中心化部署调度和流量控制;基于共享内存的通信协议;定制化的服务发现和连接池实现;定制化的服务启动和监听逻辑

课后个人总结

本节课浅入深地讲解一些框架的内部原理,主要讲解RPC框架。内容很丰富,知识点很多,通过提供的PPT资料和老师的讲解,了解了不少关于RPC框架的知识