什么是 RPC 消息协议?
消息协议的概念听起来非常的高大上,但是消息协议到底指代的是什么,看概念是很难理解的。
消息协议是指通讯双方传输的数据(消息)是如何表达描述的。
接下来我用一张图来讲讲我对消息协议的理解:
之前的文章我们已经明白了 RPC 就是远端过程调用,在上面这张图中客户端是发起调用的一方,服务端是程序被调用的一方。
在服务端中提供了一个函数(方法),这个函数需要接收两个参数(参数1,参数2),我们知道客户端和服务端是通过网络完成通信的,所以客户端如何在网络中明确自己需要调用那个函数呢?
1、客户端需要告诉服务端,它调用的函数(方法)名,以及传递相应的参数,这样服务端就明确了客户端需求
2、服务端执行了这个方法之后,同样将方法执行的结果返回给服务端,服务端就知道这次的调用的结果。
在这次简单的远端过程调用中,需要在网络中传递的是调用的方法名、参数1、参数2以及方法的执行结果,而开头说的消息协议指的就是这些需要在网络中传递的数据它的表现形式/组成形式是什么样的。
就像上面的客户端需要将调用的方法名、参数1、参数2形成一个整体传输给服务端,那么它如何将他们形成一个整体呢?
这里就需要客户端按照特定的格式将这些数据打包成一个整体,这里的特定格式指的就是消息协议。
消息协议应该如何设计?
消息协议在设计的过程中应该尽量达成以下两个目标,并且注意三个问题。
两个目标
1、性能高
- 将原始数据转换为消息数据的速度快
- 转换后的消息数据体积小
2、跨语言
RPC调用没有要求调用双方的编程语言必须相同,如果能做到跨语言调用是最好,这会方便产品开发中不同的功能服务以最合适的语言实现,然后使用 RPC 实现彼此调用。因此 RPC 调用中传输的消息数据应该尽量能让跟多的语言支持。
三个问题
边界
在网络传输中,一方可能连续向另一方多次发送消息,收到数据的一方如何界定数据中包含几条消息,这便是消息边界问题。
考虑TCP传输控制协议,在一条TCP链接中可以多次发送数据,如果发送的数据过大,就会被TCP底层实现拆解为多个数据包依次发送;而如果发送的数据过小,又可能会将几条数据组装成一个数据包进行发送。
为了解决消息边界的问题,有两种较为常用的方法:分割符法和长度声明法。
1、分割符法
顾名思义,就是在每条消息的结尾放置一种特殊的分割符(一种常用的分割符是\r\n),表示已到达本条消息的末尾。
2、长度声明法
长度声明法是在消息的起始位置,用一个固定长度的整数值(通常为4字节)声明本消息的长度,接收者先读取出长度声明,再按照声明的长度读取出相应大小的数据即可。
例如,HTTP协议同时运用了这两种方法:
HTTP/1.0 200 OK\r\n Server: Nginx\r\n Content-Type: text/html; charset=utf-8\r\n Content-Length: 5096\r\n \r\n # 此处为5096字节的数据
内容
在具体消息内容的表现形式上,可以使用文本,也可以使用二进制。
1、文本
我们可以将数据转换为具备某种格式的字符串(如 JSON),将字符串作为消息内容发送。
采用JSON这种方式,大多数编程语言都已有 JSON 转换的工具,实现起来相对便捷。但是形成的消息数据不够精简,数据中有较为无意义的,如"、{、}、,、空白字符等,在网络传输中会造成浪费。
2、二进制
二进制方式就是将数据在内存中的一些列原始二进制位或字节直接在网络中传送,而无需转换为字符串再传送。
压缩
如果消息数据过大,为了减轻网络带宽的压力,可以考虑对消息数据进行压缩处理。
就如同我们平时对一些文件、视频等使用压缩软件进行压缩来减小大小一样,我们可以在构造好数据准备发送前,先用算法将数据进行压缩处理,然后通过网络发送到对端,对端收到数据后,先进行解压缩处理,然后得到原体积数据后再进行解析。
即使是比文本数据小的二进制数据,我们仍然可以进行压缩处理。
但是需要注意的是,压缩处理是一把双刃剑,虽然能减少数据量减轻带宽压力,但是同时额外增加了压缩和解压缩的过程,压缩和解压缩在处理的时候会有时间的消耗,会导致操作系统的负担加重。有时压缩的成本可能比减少数据量带来的收益还高,就得不偿失了。
所以是否采用压缩处理,要根据具体情况权衡利弊。
Love & Share
[ 完 ]