MQTT 持久会话与 Clean Session 详解

简介: 本文介绍了MQTT持久会话的作用,并通过桌面客户端演示了Clean Session的使用。开发者可借助持久会话实现离线消息的接收及降低订阅开销。

MQTT 持久会话

不稳定的网络及有限的硬件资源是物联网应用需要面对的两大难题,MQTT 客户端与服务器的连接可能随时会因为网络波动及资源限制而异常断开。为了解决网络连接断开对通信造成的影响,MQTT 协议提供了持久会话功能。

MQTT 客户端在发起到服务器的连接时,可以设置是否创建一个持久会话。持久会话会保存一些重要的数据,以使会话能在多个网络连接中继续。持久会话主要有以下三个作用:

  • 避免因网络中断导致需要反复订阅带来的额外开销。
  • 避免错过离线期间的消息。
  • 确保 QoS 1 和 QoS 2 的消息质量保证不被网络中断影响。

持久会话需要存储哪些数据?

通过上文我们知道持久会话需要存储一些重要的数据,以使会话能被恢复。这些数据有的存储在客户端,有的则存储在服务端。

客户端中存储的会话数据:

  • 已发送给服务端,但是还没有完成确认的 QoS 1 与 QoS 2 消息。
  • 从服务端收到的,但是还没有完成确认的 QoS 2 消息。

服务端中存储的会话数据:

  • 会话是否存在,即使会话状态其余部分为空。
  • 已发送给客户端,但是还没有完成确认的 QoS 1 与 QoS 2 消息。
  • 等待传输给客户端的 QoS 0 消息(可选),QoS 1 与 QoS 2 消息。
  • 从客户端收到的,但是还没有完成确认的 QoS 2 消息,遗嘱消息和遗嘱延时间隔。

MQTT Clean Session 的使用

Clean Session 是用来控制会话状态生命周期的标志位,为 true 时表示创建一个新的会话,在客户端断开连接时,会话将自动销毁。为 false 时表示创建一个持久会话,在客户端断开连接后会话仍然保持,直到会话超时注销。

注意: 持久会话能被恢复的前提是客户端使用固定的 Client ID 再次连接,如果 Client ID 是动态的,那么连接成功后将会创建一个新的持久会话。

如下为开源 MQTT 服务器 EMQX 的 Dashboard,可以看到图中的连接虽然是断开状态,但是因为它是持久会话,所以仍然能被查看到,并且可以在 Dashboard 中手动清除该会话。

MQTT 持久会话 图1.png

同时,EMQX 也支持在 Dashboard 中设置 Session 相关参数。
EMQX Dashboard 图2.png

MQTT 3.1.1 没有规定持久会话应该在什么时候过期,如果仅从协议层面理解的话,这个持久会话应该永久存在。但在实际场景中这并不现实,因为它会非常占用服务端的资源,所以服务端通常不会完全遵循协议来实现,而是向用户提供一个全局配置来限制会话的过期时间。

比如 EMQ 提供的 免费公共 MQTT 服务器 设置的会话过期时间为 5 分钟,最大消息数为 1000 条,且不保存 QoS 0 消息。

接下来我们使用开源的跨平台 MQTT 5.0 桌面客户端工具 - MQTT X 演示 Clean Session 的使用。

打开 MQTT X 后如下所示,点击 New Connection 按钮创建一个 MQTT 连接

MQTT Client 图3.png

创建一个名为 MQTT_V3 的连接,Clean Session 为关闭状态(即为 false),MQTT 版本选择 3.1.1,然后点击右上角的 Connect 按钮。

连接的服务器默认为 EMQ 提供的免费公共 MQTT 服务器 EMQX。

创建 MQTT 连接 图4.png

连接成功后订阅 clean_session_false 主题,且 QoS 设置为 1。

订阅 MQTT 主题 图5.png

订阅成功后,点击右上角的断开连接按钮。然后,创建一个名为 MQTT_V3_Publish 的连接,MQTT 版本同样设置为 3.1.1,连接成功后向 clean_session_false 主题发布两条 QoS 1 消息。

发布 MQTT 消息 图6.png

然后选中 MQTT_V3 连接,点击连接按钮连接至服务器,将会成功接收到两条离线期间的消息。

接收 MQTT 消息 图7.png

MQTT 5.0 中的会话改进

MQTT 5.0 中将 Clean Session 拆分成了 Clean Start 与 Session Expiry Interval。Clean Start 用于指定连接时是创建一个全新的会话还是尝试复用一个已存在的会话,Session Expiry Interval 用于指定网络连接断开后会话的过期时间。

Clean Start 为 true 时表示必须丢弃任何已存在的会话,并创建一个全新的会话;为 false 时表示必须使用与 Client ID 关联的会话来恢复与客户端的通信(除非会话不存在)。

Session Expiry Interval 解决了 MQTT 3.1.1 中持久会话永久存在造成的服务器资源浪费问题。设置为 0 或未设置,表示断开连接时会话即到期;设置为大于 0 的数值,则表示会话在网络连接关闭后会保持多少秒;设置为 0xFFFFFFFF 表示会话永远不会过期。

更多细节可查看博客:Clean Start 与 Session Expiry Interval

关于 MQTT 会话的 Q&A

当会话结束后,保留消息还存在么?

MQTT 保留消息不是会话状态的一部分,它们不会在会话结束时被删除。

客户端如何知道当前会话是被恢复的会话?

MQTT 协议从 v3.1.1 开始,就为 CONNACK 报文设计了 Session Present 字段。当服务器返回的该字段值为 1 时,表示当前连接将会复用服务器保存的会话。客户端可通过该字段值决定在连接成功后是否需要重新订阅。

使用持久会话时有哪些建议?

  • 不能使用动态 Client ID,需要保证客户端每次连接的 Client ID 都是固定的。
  • 根据服务器性能、网络状况、客户端类型等合理评估会话过期时间。设置过长会占用更多的服务端资源,设置过短会导致未重连成功会话就失效。
  • 当客户端确定不再需要会话时,可使用 Clean Session 为 true 进行重连,重连成功后再断开连接。如果是 MQTT 5.0 则可在断开连接时直接设置 Session Expiry Interval 为 0,表示连接断开后会话即失效。

结语

至此,我们完成了对 MQTT 持久会话的介绍,并通过桌面客户端演示了 Clean Session 的使用。读者可参考本文借助 MQTT 持久会话实现离线消息的接收及降低订阅开销。

接下来,读者可访问 EMQ 提供的 MQTT 入门与进阶系列文章学习 MQTT 主题及通配符、保留消息、遗嘱消息等相关概念,探索 MQTT 的更多高级应用,开启 MQTT 应用及服务开发。

版权声明: 本文为 EMQ 原创,转载请注明出处。

原文链接:https://www.emqx.com/zh/blog/mqtt-session

相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
7月前
|
监控 物联网 智能硬件
MQTT 持久会话与 Clean Session 详解
【2月更文挑战第17天】
496 5
|
消息中间件 网络协议 网络性能优化
我的mqtt协议和emqttd开源项目个人理解(1) - Clean Session和Retained Message
我的mqtt协议和emqttd开源项目个人理解(1) - Clean Session和Retained Message
405 0
我的mqtt协议和emqttd开源项目个人理解(1) - Clean Session和Retained Message
|
网络性能优化
我的mqtt协议和emqttd开源项目个人理解(25) - 协议里面Clean Session为0和1的区别
我的mqtt协议和emqttd开源项目个人理解(25) - 协议里面Clean Session为0和1的区别
419 0
|
5月前
|
消息中间件 C语言 RocketMQ
消息队列 MQ操作报错合集之出现"Connection reset by peer"的错误,该如何处理
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
2月前
|
消息中间件 JSON Java
开发者如何使用轻量消息队列MNS
【10月更文挑战第19天】开发者如何使用轻量消息队列MNS
99 8
|
2月前
|
消息中间件 安全 Java
云消息队列RabbitMQ实践解决方案评测
一文带你详细了解云消息队列RabbitMQ实践的解决方案优与劣
91 8
|
1月前
|
消息中间件 存储 Kafka
MQ 消息队列核心原理,12 条最全面总结!
本文总结了消息队列的12个核心原理,涵盖消息顺序性、ACK机制、持久化及高可用性等内容。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
2月前
|
消息中间件
解决方案 | 云消息队列RabbitMQ实践获奖名单公布!
云消息队列RabbitMQ实践获奖名单公布!
|
2月前
|
消息中间件 存储 弹性计算
云消息队列RabbitMQ实践
云消息队列RabbitMQ实践
|
2月前
|
消息中间件 存储 监控
解决方案 | 云消息队列RabbitMQ实践
在实际业务中,网站因消息堆积和高流量脉冲导致系统故障。为解决这些问题,云消息队列 RabbitMQ 版提供高性能的消息处理和海量消息堆积能力,确保系统在流量高峰时仍能稳定运行。迁移前需进行技术能力和成本效益评估,包括功能、性能、限制值及费用等方面。迁移步骤包括元数据迁移、创建用户、网络打通和数据迁移。
72 4