前言

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

弱网环境下表现

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

手机终端在每次TCP断开或断网后,会即刻发起TCP重连,连接成功,会重复以前步骤依次发送连接命令(CONNECT),订阅命令(SUBSCRIBLE),表明上看,这些过程没有任何问题,但问题就在于从终端成功建立到服务器的连接,到发送订阅命令,在弱网情况下,这个过程将会变得很昂贵:从TCP建立开始的三次握手到完整的订阅命令发送完毕,考虑到TCP堆栈的每次接收数据方响应ACK,这中间终端和服务器端至少产生了10次数据交互。

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

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

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

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

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

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

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

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

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

改进点

业务改进点:

客户端的连接超时、等待超时设大一点,两秒太短,可设置长一些,比如10秒

服务器端支持在接收到用户发送CONNECT命令后,瞬间发送一些live data/hot data(早已缓存的数据),类似于HTTP请求-相应模型,目的嘛,一些热数据发送给终端要趁早,越快越好(所谓出名要趁早嘛);这个需要客户端、服务器端同时支持

协议改进点:

CONNECT命令可变头部包含"MQisdp"太多余了,学院派风格嘛

允许在连接命令中负载(payload)中携带订阅Topic字符串

允许在连接命令中表示上次连接订阅的Topic发生变化否,携带订阅业务,虽冗余,但实用。 eg:订阅的Topic没有发生变化,TOPICCHANGE:0;退订,UNSUBSCRIBE:TOPICONE;SUBSCRIBE:TOPIC_TWO

PUBLISH、PUBACK等支持的 Message Identifier 才16位,太短,实际业务无法做到全局唯一。引入mid和业务id的映射对应关系?那是状态,需要维护,代价还是蛮高的。业界流行看法,无状态化的架构才是便于横向、竖向、纵向、四方向的扩展,呵呵。最好方式就是修改使之支持字符串形式,否则维护代价高!

心跳命令PINGREQ/PINGREQ可以做到一个字节传输,节省一个字节,有些强迫症的感觉嘛

低速率网络需要做一些兼容和调整

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

严格的分层和业务解耦,会导致性能问题。好比当前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作为补充等,不一而足。

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

java mqtt丢包_MQTT 3.1协议非严肃反思录相关推荐

  1. java udp丢包重发_UDPDataPacker_Java数据报之失序和丢包

    Java数据报之失序和丢包 习惯了TCP编程,认为UDP可以包办这些问题是错误的.一个UDP应用程序要承担可靠性方面的全部工作,包括报文的丢失.重复.时延.乱序以及连接失效等问题. 通常我们在可靠性好 ...

  2. java udp丢包_linux 系统 UDP 丢包问题分析思路

    最近工作中遇到某个服务器应用程序 UDP 丢包,在排查过程中查阅了很多资料,总结出来这篇文章,供更多人参考. 在开始之前,我们先用一张图解释 linux 系统接收网络报文的过程. ●  首先网络报文通 ...

  3. Java实现抓包程序(网络协议分析程序)

    前言 本学期计算机网络要求写一个抓包程序,我通过网上查阅资料,如何实现抓包,实现了一个较为简单的抓包程序. 文章目录 前言 项目准备 一.抓包功能的基本实现 二.完整项目实现 1.界面布局 2.抓包功 ...

  4. java socket 包头包体_自定义协议封装包头、包体

    1 usingSystem;2 usingSystem.Collections.Generic;3 usingSystem.IO;4 usingSystem.Text;5 6 //消息解析器 7 pu ...

  5. 【转】使用TCP协议连续传输大量数据时,是否会丢包,应如何避免?

    [转]使用TCP协议连续传输大量数据时,是否会丢包,应如何避免? Posted on 2008-06-11 15:24 路缘 阅读(3868) 评论(0) 编辑 收藏  http://www.cnbl ...

  6. 使用TCP协议连续传输大量数据时,是否会丢包,应如何避免

    使用TCP协议连续传输大量数据时,是否会丢包,应如何避免 这个问题看看似比较容易,但很多人有不同的理解.开发中遇到是否每包(包数据可能大于1460)发送完之后需要由server->client确 ...

  7. 服务器传递文件丢包怎么回事,TCP传输协议中如何解决丢包问题

    一.回答这个问题之前,要考虑TCP协议为什么会丢包,在什么样的情况下会丢包. 1. TCP协议定义(Transimission Control Protocol)是以一种面向连接的.可靠的.基于字节流 ...

  8. java 丢包_Java数据报之失序和丢包

    习惯了TCP编程,认为UDP可以包办这些问题是错误的.一个UDP应用程序要承担可靠性方面的全部工作,包括报文的丢失.重复.时延.乱序以及连接失效等问题. 通常我们在可靠性好,传输时延小的局域网上开发测 ...

  9. java从电脑接收数据丢失_网络编程:Java数据报之失序和丢包Java -电脑资料

    习惯了TCP编程,认为UDP可以包办这些问题是错误的, 习惯了TCP编程,认为UDP可以包办这些问题是错误的.一个UDP应用程序要承担可靠性方面的全部工作,包括报文的丢失.重复.时延.乱序以及连接失效 ...

最新文章

  1. 设计模式----单件模式(c++)
  2. 苏州大学计算机科学与技术研究生分数线,【图片】18年苏州大学计算机872考研经验分享【苏州大学研究生吧】_百度贴吧...
  3. TransactionScope只要一个操作失败,它会自动回滚,Complete表示事务完成
  4. HDU--1872 稳定排序
  5. 线程池开门营业招聘开发人员的一天
  6. PTA-7-2 统计字符出现次数 (20分)
  7. 设置api密钥_我应该将我的API密钥设置多长时间?
  8. linux没有那个文件或目录_Linux安装python faiss模块
  9. linux查看和终止进程,linux 查看并终止进程
  10. 关于2020idea不能创建web项目问题
  11. jQueryEasyU校验邮箱、手机号等
  12. ISP模块之色彩增强算法--HSV空间Saturation通道调整
  13. 《指数基金投资指南》笔记整理
  14. 迭代模型(Iterative Model)
  15. 珍惜现在才能活的快乐
  16. Java 基础 第3阶段:高级应用——尚硅谷学习笔记(含面试题) 2023年
  17. 2021年度总结 -- 万粉博主的写作荣誉分享,写博客是一种心灵的修行
  18. LOL IXTAL CUP 第一日 冠军杯赛 407的夺冠之路
  19. 分享一个图片管理程序,图片批量上传,图片管理(有图片)
  20. 【概率论】3-6:条件分布(Conditional Distributions Part II)

热门文章

  1. python 运算符重载_《fluent python》第 13 章 正确重载运算符
  2. php serv-u,用php写的serv-u的web申请账号的程序_php
  3. python同时满足两个条件_python算法-快速寻找满足条件的两个数
  4. java nio 连接数_Java NIO 基础一 NIO概念
  5. js long类型精度丢失_解决js处理Long类型丢失精度的问题
  6. html5图片比例控制,按比例调整图像大小以适应HTML5画布
  7. java synoch 加锁_线程间通信 - HappyCowboy - 博客园
  8. java wps_通过WPS和WID方便地使用Java构件
  9. 图片管理系统源码_「程序员分享」基于SpringBoot开发的天猫商城源码
  10. 国风这么火,少不了古风建筑PNG格式