开始阅读前,如果你未曾了解过TCP half-open,可通过这篇文章提前了解一下。
原文:www.hivemq.com/blog/mqtt-e…
本篇文章在翻译过程中,对相关内容进行了一些删减,比如文字超链接
作者: HiveMQ Team
发布时间: March 16, 2015
更新于: 2023年6月27日
Keep Alive是MQTT协议的一个功能,它允许客户端和代理服务器通过有规律的发送名为PINGREG的控制包来维护它的连接。本篇我们会聚焦Keep Alive这个核心功能。现在让我们深入学习MQTT的Keep Alive功能,它在移动网络和维护健壮高效连接中扮演着重要的角色。
什么是MQTT 的Keep Alive功能, 它为什么重要?
MQTT的保活(Keep Alive)机制确保了连接的活跃性,并且对代理服务器提供了一种侦测客户端是否无响应或断开连接的方法。
当一个客户端和代理服务器建立了连接,它就会设置一“保活”值,这个值是一个以秒为单位的时间间隙。 在这个时间间隙内,客户端必须给代理服务器发送一个PINGREQ消息包,以表示存在一个活跃状态的客户端。代理服务器一旦收到PINGREQ消息包,它会以PINGRESP消息报回应连接一直是活跃状态的。
MQTT保活机制对连接状态监测,高效的资源利用,网络失败侦测,优雅的断开等等都是是非常重要的。
现在,让我们证实一下,为什么通过研究半开状态的TCP连接问题,保活功能是如此的重要。保活机制是如何在移动网络中应对挑战的。
MQTT中的半开状态TCP连接问题
半开状态的TCP连接问题出现在MQTT内部,它依赖于TCP来确保“可靠、有序和错误检查”的数据包在互联网上传输。尽管TCP具有健壮性,但在某些情况下,通信各方之间的同步可能会由于崩溃或传输错误而出现问题。
在TCP中,这种不完全连接的状态称为半开连接,其中通信的一方仍然不知道另一方的故障。连接端持续尝试发送消息,同时急切地等待确认。
MQTT协议发明者Andy Stanford-Clark强调,半开连接的问题在移动网络下会变得更加明显。理论上TCP/IP在sokect中断时会通知用户,但实际情况是,在移动通信和卫星通信中,每个终端都会出现无效的带有请求头的无线TCP连接,这就可能导致一种称为“黑洞”TCP会话的现象,即连接看起来是打开的,但实际上丢弃了所有传输的数据。
"虽然从TCP/IP原理上来讲,当sokect断开时会通知你,但实际情况不是那么理想,特别是在移动端和卫星链接场景中发生的一些意外情况,可能会对TCP会话造成“黑洞”现象,即出现了无效的无线TCP连接,并反复重试连接。例如,链路看似一直是开启状态,其实你所发送的任何数据都会被抛弃"
Andy Stanford-Clark on the topic "Why is the keep-alive needed?" Source
MQTT保活机制是如何运作的?
为了应对半开连接的挑战和一直保持连接状态,MQTT有一个重要的特性,称为“保活”(Keep Alive)。这种机制保证MQTT代理服务器和客户端之间的连接保持活动状态,让双方都知道对方的连接状态。
当客户端与代理服务器建立连接时,它会设置一个以秒为单位的时间间隔,称为保活间隔。此保活时间代表了代理服务器和客户端在不进行任何数据交换的最大时间间隙。根据MQTT规范,保活间隔定义如下:
“保活”是客户端传输完一个控制数据包到传输下一个控制数据包之间允许的最长空闲时间间隔。客户端需要确保发送控制数据包之间的间隔不超过“保活”值,否则,客户端必须按照“保活”值的时间间隔来发送 PINGREQ 数据包。"
只要消息以保活时间间隔内的频率完成传输,就不需要发送额外的消息来验证连接状态。然后,如果客户端在保活时间间隔内一直没有活动,它必须发送一个PINGREQ数据包给代理服务器做,以确保连接可用性和代理服务器一直可接入
如果客户端没有在保活时间间隔的1.5倍内发送任何消息或PINGREQ数据包,代理服务器将断开客户端的连接。同样,如果客户机没有在合理的时间范围内从代理服务器接收到响应,那么它也应该关闭连接。
通过使用保活机制,MQTT增强了连接的稳定性,降低了与半开连接相关的风险,并促进了代理服务器和客户端在各种网络条件下的高效通信。
保活机制是如何确保连接的活跃性的?
让我们研究一下保活消息的流程,以更深入地理解保活机制。保活特性利用了两个数据包: PINGREQ 和PINGRESP.
什么是“PINGREQ”保活消息?
当客户端想要向代理服务器发出其持续在线和活动的信号时,它会发送一个PINGREQ数据包。这个数据包是一个“心跳”消息,表明客户端仍然是连接状态。如果客户端没有发送任何其他类型的数据包,比如 PUBLISH 或 SUBSCRIBE 数据包,它必须向代理服务器发送PINGREQ数据包。客户端可以选择在任何时候发送PINGREQ数据包来验证网络连接的持续生命力。值得注意的是,PINGREQ包不包含任何有效消息负载体。
什么是“PINGRESP”保活消息?
从客户端接收到PINGREQ数据包后,代理服务器需要有用PINGRESP数据包进行响应。PINGRESP数据包作为从代理代理服务器到客户端的确认消息,用作确认其可用性和持续的连接状态。与PINGREQ数据包一样,PINGRESP数据包不包括有效消息负载体。
为了提高性能,如何设定保活设置?
- 如果代理服务器在预期时间内没有从一个客户端收到PINGREQ数据包或者其它类型的数据包,代理服务器将会关闭与此客户端的连接,并且分发提前设置好的“未来消息”。
- MQTT客户端可以设置一个合适的保活值。例如,客户端可以基于当前信号强度来调整保活时间间隔值,以便根据实际情况优化连接。
- 注意,最大保活时间间隔是18小时, 12分钟, 15秒. 相反,将保活时间间隔设置为0可以有效地停用保活机制,从而消除其对连接稳定性和管理的影响。
什么是客户端接管(Client Take-Over)?
在MQTT协议中,当一个客户端变为被断开状态,正常情况下,他会尝试重新连接,然而相对客户端来讲,某些情况下,代理服务器一直维护的其实是一个半开连接。在这种情况下,当一个客户端(即代理服务器还认为在线的客户端)开始重连,并且认为是客户端接管了连接事务,代理服务器这时就需要采取一些措施。它会立即终止与同一客户端关联的前一个连接(由客户端标识符标识) ,并与客户端建立新的连接。这种智能行为确保半开连接不会阻碍断开连接的客户端重新建立连接。通过无缝管理客户端接管,MQTT保证了在面对间歇性网络中断时的顺畅连接和弹性通信。
总结: 保活和客户端接管能提高MQTT性能
保活特性和客户端接管机制是MQTT极其重要的组成部分,可以确保在各种场景中进行可靠和高效的通信。通过通过PINGREQ和PINGRESP数据包实现保活消息,MQTT使客户端能够主动发出在线信号并验证网络连接。这种机制防止了半开连接,并允许及时检测非活动或丢失的连接。
此外,客户端接管有助于为断开连接的客户端实现无缝重连。当客户机发起重连接时,MQTT代理服务器智能地关闭与该客户机关联的任何现有的半开连接,并建立一个新连接。这个过程确保断开连接不会阻碍客户端恢复连接和平稳恢复通信的能力。
MQTT客户端必须设置适当的保活时间间隔值,同时考虑信号强度和网络条件等因素。这样可以对保活的机制进行最佳管理,并确保有效利用资源。
理解MQTT中的保活特性和客户端接管的复杂性,可以让开发人员能够构建健壮和有弹性的MQTT应用程序。通过利用这些功能,MQTT可以促进创建一个可靠的实时IoT和消息传递解决方案,这些解决方案甚至可以在具有挑战性的网络环境中蓬勃发展。