从技术上来看,私有协议设计一般需要包含三个步骤。
- 网络通信协议选型,指计算机七层网络模型中的协议选择。比如传输层的 TCP/UDP、应用层的 HTTP/WebSocket 等。
- 应用通信协议设计,指如何约定客户端和服务端之间的通信规则。比如如何识别请求内容、如何确定请求字段信息等。
- 编解码(序列化 / 反序列化)实现,用于将二进制的消息内容解析为程序可识别的数据格式。
网络通信协议选型
从功能需求出发,为了保证性能和可靠性,几乎所有主流消息队列在核心生产、消费链路的协议选择上,都是基于可靠性高、长连接的 TCP 协议。
应用通信协议设计
从应用通信协议构成的角度,协议一般会包含协议头和协议体两部分。
协议头包含一些通用信息和数据源信息,比如协议版本、请求标识、请求的 ID、客户端 ID 等等。
协议体主要包含本次通信的业务数据,比如一串字符串、一段 JSON 格式的数据或者原始二进制数据等等。
设计的原则是:请求维度的通用信息放在协议头,消息维度的信息就放在协议体。
协议头的设计
请求头一般需要携带协议版本、请求标识、请求的 ID、客户端 ID 等信息。而返回头,一般只需要携带本次请求的 ID、本次请求的处理结果(成功或失败)等几个信息。
协议体的设计
协议体的设计就和业务功能密切相关了。因为协议体是携带本次请求 / 返回的具体内容的,不同接口是不一样的,比如生产、消费、确认,每个接口的功能不一样,结构基本千差万别。
协议在实现上首先需要具备向后兼容的能力,后续的变更(如增加或删除)不会影响新老客户端的使用;然后协议内容上要尽量精简(比如字段和数据类型),这样可以降低编解码和传输过程中的带宽的开销,以及其他物理资源的开销;最后需要协议版本管理,方便后续的变更。
编解码实现
在序列化和反序列化中,最重要的就是 TCP 的粘包和拆包。我们知道 TCP 是一个“流”协议,是一串数据,没有明显的界限,TCP 层面不知道这段流数据的意义,只负责传输。所以应用层就要根据某个规则从流数据中拆出完整的包,解析出有意义的数据,这就是粘包和拆包的作用。
粘包 / 拆包的几个思路就是:
- 消息定长。
- 在包尾增加回车换行符进行分割,例如 FTP 协议。
- 将消息分为消息头和消息体,消息头中包含消息总长度,然后根据长度从流中解析出数据。
- 更加复杂的应用层协议,比如 HTTP、WebSocket 等。
此文章为11月Day3学习笔记,内容来源于极客时间《深入拆解消息队列 47 讲》