在分布式系统中,RPC尤为重要。SRMP是新生命团队专门为了RPC框架而设计的通信协议,既能覆盖内网高速通信,也能覆盖物联网嵌入式设备。
目标定位
经过十多年实战经验积累以及多方共同讨论,新生命团队(https://github.com/newlifex)制订了一种简单而又具有较好扩展性的RPC(Remote Procedure Call)协议。
全称:简易远程消息交换协议,简称: SRMP(Simple Remote Messaging Protocol)
SRMP主要定位于以下场景:
- 内网高速通信,大吞吐量(>10万tps)、低延迟(<1ms)
- 外网远程通信,稳定可靠,海量连接(>10万)
- 物联网硬件设备,容易简单实现协议
- 支持TCP/UDP/串口/蓝牙BLE等多种通信方式
基础格式
协议格式: 1 Flag + 1 Sequence + 2 Length + N Payload
1个字节标识位,标识请求、响应、错误、单向广播等;
1个字节序列号,用于请求响应包配对;
2个字节数据长度N,小端字节序,指示后续负载数据长度(不包含头部4个字节),解决粘包问题;
N个字节负载数据,数据内容完全由业务决定,最大长度65534=64k-2。
负载数据大于等于64k时,数据长度字段填65535(0xFFFF),启用后续4字节扩展长度,最大长度4G(0xFFFFFFFF),此时头部总长度是8字节。
嵌入式物联网硬件设备建议直接忽略扩展长度,仅需支持4字节头部,限制负载数据小于64k。
采用固定2字节表示长度,方便任意语言接入,特别是嵌入式实现,这一点上完胜变长的七位压缩编码整数。内网高速通信可实现8字节头部扩容,而物联网嵌入式设备则可以直接不考虑扩容。
1字节序列号,主要用于UDP通信、串口通信、无线通信等做请求与响应的匹配,这是多路复用的根基所致。
RPC请求与响应
SRMP主要分为请求和响应两种指令。
请求格式
RPC请求封包由4字节头部和数据体部分组成,头部长度位指示了数据体部分总长度。数据体由接口名和请求参数两部分组成,二者都是以压缩长度开始指示数据长度。
如若有扩展需要,可作为请求参数的一部分传输,整体格式不变。例如,某些场景需要Token令牌或者TraceId追踪,实际上可以作为请求参数一部分来整体封包。
请求参数默认采用Json序列化封包,高速接口支持直接以Packet作为参数,绕开序列化的成本开支。强烈建议10000tps以上的接口采用高速Packet传参,此时接口入参只能有一个Packet参数。用户自己对参数进行二进制序列化。
在高并发大吞吐系统中,序列化成本占据整体通信耗时的70%以上,远远超过网络开支。
字节 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
1 Flag | 请求0 | 单向 | 保留 | |||||
1 Seq | 序列号(0~255) | |||||||
2 Length | 数据长度(0~65534) | |||||||
Body | S 字符串长度 | 服务接口名称(Action) | ||||||
N 字节数组长度 | 请求参数(Json/Packet) |
响应格式
RPC响应封包由4字节头部和数据体部分组成,头部长度位指示了数据体部分总长度。数据体由接口名、响应代码、响应数据三部分组成,其中接口名和响应数据以压缩长度开始指示数据长度。响应代码固定4字节整数,0表示成功,部分超场景200也表示成功,其它表示错误码。
如若有扩展需要,可作为响应数据的一部分传输,整体格式不变。
响应数据默认采用Json序列化封包,高速接口支持直接以Packet作为响应数据,绕开序列化的成本开支。强烈建议10000tps以上的接口采用Packet作为响应数据,此时接口返回类型必须是Packet。用户自己对参数进行二进制序列化。
在高并发大吞吐系统中,序列化成本占据整体通信耗时的70%以上,远远超过网络开支。
字节 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
1 Flag | 响应1 | 错误 | 保留 | |||||
1 Seq | 序列号(0~255) | |||||||
2 Length | 数据长度(0~65534) | |||||||
Body | S 字符串长度 | 服务接口名称(Action) | ||||||
4 响应代码(Code) | ||||||||
N 字节数组长度 | 响应数据(Json/Packet) |
总结
SRMP协议采用极为简单的格式实现,便于不同编程语言以及嵌入式硬件设备的接入。