RPC框架分层设计
基本概念
-
远程函数调用RPC(Remote Procedure Calls)
需要解决的问题:
- 函数映射
- 数据转换成字节流
- 网络传输
-
RPC概念模型
User,User-Stub RPC-Runtime Server-Stub Server
一次RPC的完整过程
- IDL(Interface description language)文件:IDL通过一种中立的方式来描述接口,使得再不同平台上运行的对象和用不同语言编写的程序可以相互通信
- 生成代码:通过编译器工具把IDL文件转换成语言对应的静态库
- 编解码:从内存表示到字节序列的转换成为编码,反之为解码,也常叫做序列化和反序列化、
- 通信协议:规范了数据在网络中的传输内容和格式。除必须的请求/响应数据外,通常还包含额外的元数据
- 网络传输:通常基于成熟的网络库走TCP/UDP传输
- RPC的好处
远程过程调用(RPC)作为一种重要的分布式通信机制,在现代软件开发中发挥着关键作用。它带来了许多显著的好处,通过将远程的服务调用抽象为本地调用,为构建高效协作和稳固系统奠定了坚实的基础。
-
单一职责,有利于分工协作和运维开发:RPC的设计原则强调将服务分割为独立的模块,每个模块承担特定的职责。这种单一职责的架构风格有利于团队分工协作,不同团队可以独立开发和维护各自的模块,减少代码耦合,提高开发效率。同时,单一职责的服务也更容易进行故障定位和修复,从而提高系统的可维护性。
-
可扩展性强,资源使用率更优:RPC允许系统以模块化方式进行水平扩展。每个服务模块可以独立扩展,无需整体扩展整个应用。这种模块化扩展方式有效地提高了资源的利用率,避免了不必要的资源浪费。系统可以根据实际需要,灵活地分配资源,从而实现更高的吞吐量和更低的延迟。
-
故障隔离,服务的整体可靠性更高:RPC通过明确定义接口和协议,将服务与服务之间的交互清晰地划分开来。这种隔离性使得当一个服务出现故障时,不会影响到整个系统的稳定性。系统可以在部分故障的情况下依然保持正常运行,通过快速故障切换或回退机制,提高整体的可靠性和稳定性。
分层设计
以Apache Thrift为例
-
编解码层
-
生成代码:
-
数据格式
- 语言特定的格式:许多编程语言都内建了将内存对象编码为字节序列的支持,例如java中的java.io.Serializable
- 文本格式:JSON,XML,CSV等文本格式,具有人类可读性
- 二进制编码:具备跨语言和高性能等有点,常见有
Thrify的BinaryProtocol,Protobuf等
-
二进制编码:TLV编码
-
Tag,标签,可以理解为类型 -
Length,长度 -
Value,值,Value也可以是个TLV结构eg:
struct Person{ 1: required string userName, 2: optional i64 favoriteNumber, 3: optional list<string> interests }
-
-
选型
- 兼容性:支持自动增加新的字段,而不影响老的服务,这将提高系统的灵活度
- 通用性:支持跨平台,跨语言
- 性能:从空间和时间两个维度来考虑,也就是编码后数据大小和编码耗费时长
-
-
协议层
-
概念
- 特殊结束符:以一个特殊字符作为每个协议单元结束的标志,例如
[message body][\r\n][message body][\r\n] - 变长协议:以定长加不定长的部分组成,其中定长的部分需要描述不定长的内容长度,
[length][message body][length][message body]
- 特殊结束符:以一个特殊字符作为每个协议单元结束的标志,例如
-
协议构造
LENGTH: 数据包大小,不包含自身HEADER MAGIC:表示版本信息,协议解析时侯快速校验SEQUENCE NUMBER:表示数据包的seqID,可用于多路复用,单连接递增HEADER SIZE:头部长度,从第14个字节开始计算到PAYLOAD之前PROTOCOL ID:编解码方式,有Binary,Compact两种TRANSFORM ID:压缩方式,如zlib和snappyINFO ID:传递一些定制的meta信息PAYLOAD:消息体
-
协议解析
-
-
网络通信层
-
Sockets API
-