mqtt 3.1协议非严肃反思录 -凯发k8网页登录

记录工作/学习的点点滴滴。

mqtt 3.1协议非严肃反思录

前言

mqtt 3.1协议在弱网络环境下(比如2g/3g等)表现不够好,因此才有了反思。

弱网环境下表现

手机等终端在弱网络环境下丢包情况会非常明显,连接mqtt server成功率很低。相比单纯的请求-相应模型的http,其成功率会比mqtt订阅成功高很多。

手机终端在每次tcp断开或断网后,会即刻发起tcp重连,连接成功,会重复以前步骤依次发送连接命令(connect),订阅命令(subscrible),表明上看,这些过程没有任何问题,但问题就在于从终端成功建立到服务器的连接,到发送订阅命令,在弱网情况下,这个过程将会变得很昂贵:

从tcp建立开始的三次握手到完整的订阅命令发送完毕,考虑到tcp堆栈的每次接收数据方响应ack,这中间终端和服务器端至少产生了10次数据交互。

在网络变化频繁或者不太稳定的2g/3g网络环境下,这种过程显得有些冗长和不适应,同时会加重已经不堪的弱网络负载的负担。

弱网下,在任何一个阶段的执行过程中,都有可能产生突发性的网络中断的问题:

  1. 无法成功建立tcp链接,或死在三次握手期间,或数据包丢失在握手之后,或客户端连接超时过小

  2. 建立连接后,发送connect命令后,或没接收到tcp ack确认包,或客户端等待延时太小,导致订阅命令交互失败

  3. 发送subscrible命令后,但服务器端没收到,或因为丢包,或网络已断开,导致发送subscrible命令失败

  4. 成功发送subscrible命令后,或移动网络断开了(有些运营商针对认为http的请求有超时判断),或等待超时,导致订阅失败

tcp是无感知的虚拟连接,中间断开两端不会立刻得到通知,否则就用不着心跳保活机制了。

举一个例子,线上的服务器根据日志分析,只接收到连接命令(connect)但没有后续的订阅命令(subscrible)的情况,每天有上百万级别的数量。

总之,针对低速率弱网络环境,mqtt表现不怎么好。

改进点

业务改进点:

  1. 客户端的连接超时、等待超时设大一点,两秒太短,可设置长一些,比如10秒
  2. 服务器端支持在接收到用户发送connect命令后,瞬间发送一些live data/hot data(早已缓存的数据),类似于http请求-相应模型,目的嘛,一些热数据发送给终端要趁早,越快越好(所谓出名要趁早嘛);这个需要客户端、服务器端同时支持

协议改进点:

  1. connect命令可变头部包含"mqisdp"太多余了,学院派风格嘛
  2. 允许在连接命令中负载(payload)中携带订阅topic字符串
  3. 允许在连接命令中表示上次连接订阅的topic发生变化否,携带订阅业务,虽冗余,但实用。 eg:订阅的topic没有发生变化,topicchange:0;退订,unsubscribe:topicone;subscribe:topic_two
  4. publish、puback等支持的 message identifier 才16位,太短,实际业务无法做到全局唯一。引入mid和业务id的映射对应关系?那是状态,需要维护,代价还是蛮高的。业界流行看法,无状态化的架构才是便于横向、竖向、纵向、四方向的扩展,呵呵。最好方式就是修改使之支持字符串形式,否则维护代价高!
  5. 心跳命令pingreq/pingreq可以做到一个字节传输,节省一个字节,有些强迫症的感觉嘛
  6. 低速率网络需要做一些兼容和调整

有些建议看似冗余,批量或打包处理总比单个处理更高效一些、更节省资源,弱网络环境要求交互要尽可能的少,数据嘛要的是瞬间抵达,越快越好。

严格的分层和业务解耦,会导致性能问题。好比当前linux内核的tcp/ip网络堆栈分层很清晰,每一层都各司其职,但和直接略过内核态直接运行在用户态(user space)的packet i/o相比,处理性能不是在一个档次上,比如netmap 、dpdk等。

mqtt-sn

针对没有tcp/ip等网络堆栈支持的终端环境,mqtt爱莫能助了。

在一些类似于传感器电子元件中,资源十分受限,计算能力不足,嵌入tcp/ip网络堆栈不现实,比较好的方式基于ieee 802.15.4用于低速无线个人域网(lr-wpan)的物理层和媒体接入控制层规范之上发送udp数据包,每一个数据包最大128个字节。

mqtt-sn(mqtt for sensor networks)协议就是为了非常受限类似传感器而设的,协议流程架构比较有趣:

更多协议细节,有待进一步阅读。

tcp不是最适合的移动网络传输协议

先来算一下网络传输的字节数。

以太网帧头至少18个字节,ip头固定20个字节,tcp头20个字节(udp头部8个字节),再加上电信宽带计费的pppoe的8个字节:

  • tcp数据包头部信息至少占有66个字节
  • udp数据报头部信息至少占有54个字节

udp可以比tcp节省12个字节。

mqtt-sn协议选择使用udp,可以看出其在节省资源方面的努力。

再看看弱网环境。

  • 在网络可达情况下,udp可以在tcp建立第一次握手期间就已经把数据送达目的地
  • 完成三次握手期间,udp客户端和udp服务器在数据层面可以完成一次完整的交互(ping-pong)

在网络不好的情况下,udp的时效性会好于tcp,tcp长连接中间交换过多、使之建立完整交互的过程成功率就很低。此种情况udp的低延迟和实时性呈现的结果会表现的很突出。

tcp或http理论上是可靠连接,但是在网络不好的时候,也不是那么可靠。客户端一般提交http请求之后,没有确认是否提交成功,在弱网环境下会产生丢包,服务器端嘛收不到。另tcp网络堆栈会存在数据包重发机制 应用层重发请求,可能会导致内核处理多次数据包的重发(还有拥塞窗口会收缩,发包速度减慢),可能会加重弱网络的负载。

和tcp相比,udp的无连接,代表了它快速,资源消耗小,突出表现就是延迟较小。至于数据包丢失没有重传,上层的业务层面应用协议/机制可以确保丢失的数据包重发或补发等,并且会更透明,安全的控性权。而tcp的包重发,上层应用没有控制权限。

连接协议方面:

  • tcp面向连接会产生状态管理和维护,成本不小,比如经常看到的客户端reset异常等。一次完整的请求周期必须固定在一台服务器上
  • udp无连接的特性。每次请求的数据包可以随机分配到不同的机器上进行处理,可以做到完全无状态化横向扩展

总之,要实时性特诊,或者快速抵达终端的特性,不妨考虑一下udp。不过呢,很多时候udp和tcp大家会混合着使用,会互相弥补其不足。

小结

若mqtt协议不能够满足业务需求,或许可考虑选择定制,或简化流程,或使用udp重新实现,或者使用tcp/http作为补充等,不一而足。

想想,还真有点小激动呢! ------ 《万万没想到》王大锤

posted on 2014-12-12 10:19 nieyong 阅读(31080) 评论(17)     所属分类: mqtt

# re: mqtt 3.1协议非严肃反思录 2014-12-16 17:20

你好,谢谢你的文章。
我们有个手机app,目前的方案是实时数据直接socket连接(不好的地方是客户端服务端都要写代码),想全面转向mqtt(这样服务端就专注于从mqtt对立里面获取数据,进行业务处理,并发送消息即可),逻辑上应该更清楚,代码开发也方便。但是听你这个介绍有点犹豫了,要不要改呢?请听你的指教!  回复     

# re: mqtt 3.1协议非严肃反思录 2014-12-17 10:25 nieyong

@tangsir
目前除了mqtt,暂时找不到比它更好的业界标准了。建议选择mqtt 3.1.1协议:
支持客户端在发送完毕connect之后,无须等待服务器响应直接发送其余命令
支持服务器和客户端两端暂时会话保存,上次连接之后,再次connect,会话标志位true,可无须发送subscrible命令
具体请参考:
  回复     

# re: mqtt 3.1协议非严肃反思录 2014-12-17 23:21

谢大神!@nieyong
  回复     

# re: mqtt 3.1协议非严肃反思录 2014-12-18 22:06 nieyong

@tangsir
措辞有问题,可不是什么大神,呵呵。
只是总结而已。  回复     

# bad piggies game 2014-12-19 15:55

措辞有问题,可不是什么大神,呵呵。  回复     

# jogos frin 2014-12-22 11:55

措辞有问题,可不是什么大神,呵呵。  回复     

# jogos frin 2014-12-22 11:55

措辞有问题,可不是什么大神,呵呵。   回复     

# friv school 2015 2014-12-25 11:07

措辞有问题,可不是什么大神,呵呵  回复     

# re: mqtt 3.1协议非严肃反思录 2015-05-07 21:33

你好我们有手机设备也有硬件设备,不同的设备需要根据不同的情况推送各自的数据,如果我们有10万个终端,我们需要建立10万个topic吗?有没有其它地方法谢谢?  回复     

# re: mqtt 3.1协议非严肃反思录 2015-05-08 09:49 nieyong

@kdm
其实,灵活一点是不需要建立10w个topic的,根据clientid就可以  回复     

# re: mqtt 3.1协议非严肃反思录 2015-05-14 21:53

@nieyong
请教一下根据clientid如何做,请大神指导  回复     

# re: mqtt 3.1协议非严肃反思录 2015-05-15 10:04 nieyong

@kdm
clientid等同于topic就行  回复     

# re: mqtt 3.1协议非严肃反思录 2015-05-15 17:45

@nieyong
那还是每个设备一个topic对吧。topic的主题为clientid.  回复     

# re: mqtt 3.1协议非严肃反思录 2015-05-18 16:41 nieyong

@kdm
是的,比如根据协议,只需要注册一次,服务器端可持久化topic和clientid的对应关系,后面不需要再次注册等。或者再简单一些,就直接根据clientid作为topic就行。

怎么说呢,越是海量用户/终端的系统,协议交互层面需要越简单,架构层面也是如此。  回复     

# re: mqtt 3.1协议非严肃反思录 2015-06-12 13:56

看了这篇文章,实话说有点不以为然

本文说了半天,就是一个问题,当subscribe命令在交互时候出现问题怎么办?

回到协议本身,事实上是很简单的一个答案,只有收到正确的suback命令才能认为subscribe成功,否则客户端有义务不断地重复发送subscribe。

而判断正确返回否则管理着重发的机制本来就是message queue的精髓所在,在客户端维护一个最基础记录subscribe的queue,原始意义上并不是特别难。

至于本文所提的用udp协议,或者和改造协议部分,重传部分数据的方法,只会使协议复杂度变高很多,出错可能性增加;在高并发的环境中,并不可取。而相对来说,客户端做更改难度小很多。  回复     

# re: mqtt 3.1协议非严肃反思录 2015-09-13 09:32

subscribe让服务器自动订阅,把客户端subscribe功能禁止掉  回复     

# re: mqtt 3.1协议非严肃反思录 2016-05-23 07:34

this is very nice. thank you.  回复     


只有注册用户后才能发表评论。


网站导航:
              
 

公告

所有文章皆为原创,若转载请标明出处,谢谢~

新浪微博,欢迎关注:

导航

2014年12月
30123456
789101113
141517181920
212224252627
28293031123
45678910

统计

常用链接

留言簿(58)

随笔分类(129)

随笔档案(149)

个人收藏

最新随笔

搜索

最新评论

阅读排行榜

评论排行榜

网站地图