这一小节,我们来探讨RPC中的通信协议。
通信协议是一组规则和标准,用于规范RPC的请求与响应行为。协议定义了数据传输的方式、数据格式、传输速度以及错误控制等方面的内容。
为了保证性能与可靠性,几乎所有的主流RPC框架在传输层协议的选型上都使用的是基于可靠性、长连接的TCP协议。
而我们这里说的协议是应用层协议,目前业界的通信协议有两种选择,公有协议与私有协议。
公有协议是指由公共的组织或机构公开定义的具有通用性的协议;比如DNS、FTP、HTTP、JMS、STOMP等协议;
私有协议是开发者根据自身的功能与需求设计的,一般不具备通用性;
那在RPC的范畴里,常用的RPC协议有JSON、XML、gRPC、dubbo2、HTTP等
这些协议没有好坏之分,RPC框架的开发者在协议选型方面会基于协议的紧凑性、通用性、灵活性、扩展性、是否跨语言等方面进行综合考虑,最终决定是使用公有协议还是私有协议。
比如eureka使用的是HTTP协议,dubbo默认使用的dubbo2协议是私有协议;nacos 1.0版本使用的是HTTP协议,为了提升性能在2.0版本进入了gRPC协议。
那如何设计一个良好的私有协议呢?一个好的通信协议要满足一下特点
● 协议可靠性要强,不能丢数据
● 性能要高
● 协议要简洁紧凑,带宽的利用率要高
● 要具备可扩展能力,方面功能的增减
从技术上来看,设计私有协议一般要包含三个步骤
1. 网络通信(传输层协议)选型
2. 应用通信协议设计
从应用通信协议的构成角度,协议一般包含协议头与协议体两部分。
● 协议头【协议版本号,请求标识、请求ID、客户端ID、加密方式、序列化方式等】
● 协议体【通信的业务数据】
3. 编解码(序列化/反序列化)
数据在网络传输是通过二进制流的形式,所以consumer发送数据之前要序列化【将原始数据转换为二进制流】,provider在收到数据后要进行反序列化【将二进制流转换为原始数据】
过程中最重要的就是TCP的黏包和拆包。原因是TCP是一个面向流的协议。面对一串二进制数据,TCP是不清楚数据的含义以及边界,只负责传输,所以在应用层就需要根据某个规则从流数据中拆出一个个请求对应的完整的二进制流。
处理黏包拆包的思路有:
● 消息定长
● 包尾部增加回车换行符进行分割,比如FTP协议
● 将消息分为消息头&消息体,消息头中包含固定的开始字符,以及消息的总长度,然后根据长度从流中解析出数据
接下来我们介绍下dubbo2协议:
Dubbo2 协议是基于 TCP 传输层协议之上构建的一套 RPC 通信协议。协议格式如下:
Octet :字节开始下标
Bit:位开始下标
● Magic - Magic High & Magic Low (16 bits) 固定值:0xdabb
● Req/Res (1 bit) 请求: 1; 响应: 0
● 2 Way (1 bit) 是否期望从服务器返回值 0 不期望 1 期望
● Event (1 bit) 标识是否是事件消息,比如心跳; 0 不是 1 是
● Serialization ID (5 bit) 序列类型 最大可表示32中序列化类型
● Status (8 bits) 响应状态,只在Req有用
● Request ID (64 bits) 请求的唯一标识
● Data Length (32 bits) 序列化后的内容长度,int类型
● 真实数据
可以看到,dubbo的协议有紧凑的部分,比如第三个字节标识了4种属性,但也有不完善的地方,列举一下:
● 对于网关代理组件不友好,网关无法通过协议头判断要访问的资源,需要把协议体解析后才知道
● 没有根据请求响应类型分别设计协议头,可以精细定制协议,比如请求数据中,不需要status字段 响应类型不需要2 Way
● 没有预留扩展字段。比如想增加请求上下文的功能或者增加TraceId,只能在attachment 中加
最后,我们自定义一个协议:
+------------------------------------------------------------------------------------------+
| 魔数 2byte | 协议版本号 1byte | 序列化算法 1byte | 报文类型 1byte |
+------------------------------------------------------------------------------------------+
| 状态 1byte | 消息 ID 8byte | 数据长度 4byte |
+------------------------------------------------------------------------------------------+
| 数据内容 (长度不定) |
+------------------------------------------------------------------------------------------+
这个协议比较简单,就不介绍了,作为之后实战项目中的通信协议。