6

消息队列面试解析 - 传输协议

 2 years ago
source link: https://segmentfault.com/a/1190000041102584
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

消息队列面试解析 - 传输协议

应用程序之间要想互相通信,一起配合来实现业务功能,还需传输协议支持。

传输协议就是应用程序之间对话的语言。设计传输协议,并无太多规范和要求,只需通信双方的应用程序都能正确处理该协议&&无歧义。

1.1 分隔符

传输协议也是种语言,传输数据时,首要解决的就是断句。

对传输层,收到的数据是怎样的?

就是一段段的字节,但因网络不确定性,你收到的分段并不一定是生产者发出去的分段。

那在协议中也加上“标点符号”不就行?

而且,并不需要像自然语言中那么多种的标点符号,而只需定义一个分隔符即可。

这办法的确可行,很多传输协议就采用这种方法,比如HTTP 1.0协议,它的分隔符是换行(\r\n)。但这有个问题:自然语言中,标点符号是专用的,它没有别的含义,和文字天然区分。
但在数据传输过程,无论你定义什么字符作为分隔符,理论上都有可能会在传输的数据中出现。

那如何区分“数据内的分隔符”和真正的分隔符?

得在发送数据阶段,加上分隔符前,把数据内的分隔符转义,收到数据后再转义回来。
这的确是个麻烦过程,损失了一些性能。

1.2 预置长度

更加实用的方法。

给每句话前面加一个表示这句话长度的数字,收到数据时,按长度读。

如:03下雨天03留客天02天留03我不留
这里固定使用2位数字存放长度,每句话最长可支持99个字。接收后的处理就简单了,先读取2位数字03,知道接下来3个字是第一句话,那就等这3个字都收到,即可作为第一句话,同理读第二句话、第三句话。

这很好解决断句问题,实现比分隔符方法更简单,性能也更好,是普遍采用的分隔数据的方法。

redis 的 aof 文件好像就是前置长度哦,经典方案无处不在~

前置长度是不是也有类似问题呢,03也可能是正常文字里的内容,也是要转义吧?

你可以想一下,最好自己实现一下接收数据进行解析的代码,你就会明白,前置长度无需转义。因为解析时,可明确知道当前读到的这个位置应该是长度还是真正数据,它不需要根据数据流中的内容来确定。

2 双工收发

2.1 单工通信

任一时刻,数据只能单向传输,一个人说时,另一个人只能听。
HTTP 1.0协议就是这样,客户端与服务端建立个连接后,客户端发个请求,直到服务端返回响应或请求超时,这段时间内,这个连接通道上不能再发其他请求。

这种单工通信,效率低,很多浏览器和APP为解决性能问题,只能同时在服务端和客户端间创建多条连接。

单工通信时,一句对一句,请求和响应按序依次收发,有个天然对应关系。就像被女朋友质问时,女朋友问一句,你才敢答一句。这沟通效率有何意义?

2.2 双工通信

而TCP连接是全双工通道,可同时进行数据的双向收发,互不影响。要提高吞吐量,应用层协议必须支持双工通信。

双工通信,不管是客户端还是服务端建立好连接后,双方都能基于该socket进行收发消息,而不是服务器只能accept到message后才能做些处理。

如果说你和你对象有边听边说的本事,换成双工协议后,基本就是在和女人讲道理,你们就会混乱到分不清到底在回答问题or陈述观点。
并发下,顺序也无法保证。实际设计协议时,一般不关心顺序,只需确保请求和响应能够正确对应。

解决对应问题

发送请求时,给每个请求加个序号:该序号在本次会话内保证唯一,然后在响应中带上请求的序号,这就能把请求和响应对应上。

加上序号后,即使如抢答一般混乱,也分得清到底在说啥。

你和你对象就能对自己发出去的请求来编号,回复对方响应的时候,带上对方请求的编号即可。这就解决了双工通信的主要问题。

在一次会话过程中,开头的先是唯一序列号吗?然后后面跟数据长度,再是内容吗?
那接到消息的一方,如何分辨序列号的长度大小,做到区分序列号和内容前的数据长度信息?

开头就肯定是数据长度,序号也是数据的一部分!所以应该在数据长度的后面。

设计传输协议时,只要双方应用程序能够识别传输协议,互相交流即可,并没啥绝对的规范。

首要得解决断句,有“分隔符”和“前置长度”两种断句方案。

使用ID来标识请求与响应对应关系的方法,是比较通用的实现双工通信的方法,可有效提升数据传输的吞吐量。

解决了断句,实现了双工通信,配合专用序列化方法,即可实现高性能的网络通信协议,实现高性能的进程间通信。很多MQ、RPC框架都是用这种方式来实现它们自己的私有应用层传输协议。

简单的高性能通信程序:你和你对象三组对话,服务端是你对象,客户端是你自己,让俩人在客厅碰见一百万次,记录下总共耗时。

https://github.com/WangYangA9...
https://sourcegraph.com/githu...


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK