首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >MQTT:To Retain or Not To Retain?

MQTT:To Retain or Not To Retain?

作者头像
Hello工控
发布于 2025-05-21 14:16:34
发布于 2025-05-21 14:16:34
1.1K0
举报
文章被收录于专栏:Hello工控Hello工控

关于本期内容,涉及到Retain保留这个选项,在整理资料,下图有个提问很有代表性,我们的标题就是采纳他的:

所以,要回答这个问题,我们首先的详细了解Retain在MQTT的定义和作用,接下来,我详细介绍下MQTT Retain。

代码语言:javascript
复制

什么是保留消息(Retained Messages)?

MQTT 保留消息是带有 retain 标志设置为 true ( retain 标志 = 1 )的 PUBLISH 数据包。如果你熟悉 MQTT,你会知道 MQTT 数据包具有各种属性和标志。其中一个可用的标志是 retain 标志,它告诉代理必须存储消息,换句话说,就是保留消息。

接收到带有 Retain 标记的消息时,MQTT 代理必须存储该消息,并仅存储发布该消息的主题的最新消息。因此,对这个主题感兴趣的订阅者即使离线,也可以随时重新连接以接收最新消息,而无需等待发布者在订阅后发送下一条消息。

如下图所示,当客户端订阅某个主题时,如果该主题存在保留消息,那么该保留消息会立即发送给客户端。

Retain 保留消息的结构

在前期关于 MQTT 数据包的文章中,我们知道典型的消息结构看起来像这样:

MQTT Control Packets(MQTT控制包)了解吗?

The control field and remaining length in the fixed headers of an MQTT packet.
The control field and remaining length in the fixed headers of an MQTT packet.

在控制字段中,有一些标志Flags可用,包括 retain 标志。一个 retain 标志被设置为 true 的控制数据包示例如下:

我们详细举例说明,下面是一个带retain标志的Publish数据包:

我们详细的看看上述Publish发布的数据包含义:

  • 31:表示这是一个 QoS 0 的 PUBLISH 数据包, DUP 标志为假, retain 标志为真
  • 10:表示 MQTT 数据包可变头部剩余长度为十进制的 16
  • 000c :表示主题名称字符长度为12
  • 72657461696e2f746f706963: 表示主题名称 retain/topic
  • 31: 此消息的负载,UTF-8 编码的“1”字符

要删除主题 retain/topic 上的保留消息,您可以发送一个负载为零字节的 PUBLISH 数据包,如下所示:

代码示例:

下面的例子说明了怎样才能删除主题retain上的保留信息:

QoS并不影响retain保留的消息,就算QoS=0也不影响,只有当message=null且retain = true,这两个条件满足才能删除保留信息。

图片
图片

在什么情况下使用 MQTT 保留消息?

虽然发布-订阅模式允许发布者与订阅者解耦,但这种模式也有一个缺点,即订阅者不能主动从发布者那里获取消息。订阅者何时收到消息取决于发布者何时发布消息,这在某些场景中是不方便的。

新的订阅者可以通过保留消息立即获取最新数据,而无需等待不可预测的时间。以下是一些示例:

  • 智能家居设备只在状态改变时发送状态数据,但控制 APP 需要在用户打开 APP 时知道设备的当前状态。
  • 传感器上报数据的间隔可能非常长,但订阅者在订阅后可能需要立即获取最新数据。
  • 不常更改的属性,如传感器版本和序列号,可以发布为保留消息,以便后续订阅者获取信息。
  • MQTT 旨在也能在不稳定的网络环境中表现良好——在这种情况下,连接到 MQTT 中介器的设备可能会意外地断开连接并重新连接。在主题上保留最后已知的消息可以让在断电后上线的任何设备立即获取最新的消息,而无需等待新的更新。

如何使用 MQTT 保留消息?

对于 MQTT 客户端 SDK,通常有 API 或参数来设置Retain 标志。例如,paho MQTT Java 客户端库和 Erlang MQTT 客户端 emqtt。

对于 MQTT 客户端工具,无论是命令行界面还是图形界面,都应该能找到设置 Retain标志的地方。

在本文中,我们不会深入探讨编程 SDK。我们将使用开源跨平台 MQTT 5.0 桌面客户端-MQTTX 来演示 MQTT 保留消息。

我们先创建一个连接,名称:Retain Demo,Host用默认的emqx的公用服务器,创建完成后,点击右上角的连接Connect按钮:

成功连接后,我们发布一条消息到主题:sensor/s1,注意这个没有选择Retain标志。

接下来,发布两条保留消息到这个主题:sensor/s2

然后创建一个订阅,点击New Subscription即可:

我们这里订阅主题采用通配符+,这将匹配主题 sensor/s1 和 sensor/s2

最后,我们将看到订阅成功接收到第二个保留消息,既不是针对 sensor/t1 的普通消息,也不是针对sensor/t2的第一个保留消息。这表明 MQTT 代理只会为每个主题存储最新的保留消息。

当然,除了这个消息外,还有其他sensor/temperature,sensor/humi11等等主题的Retain消息,可能这个公用的代理服务器太多Retain相关的主题消息,估计用了后没有删除。

MQTT 中 QoS 的常见问题

Q: 我可以在 MQTT 中配置保留消息的存储机制或位置吗?

A: 在 MQTT 中,保留消息的存储机制和位置通常由您使用的 MQTT 代理实现决定。MQTT 规范并没有为保留消息的存储提供具体的指导或要求。

Q: 我可以将保留消息与 MQTT 质量等级(QoS)一起使用吗?

A: 可以,保留消息和QoS是独立的两个概念,在使用保留消息时,您可以根据具体需求选择合适的 QoS 级别,无论是简单的交付(QoS 0)、有保证的交付(QoS 1),还是精确一次的交付(QoS 2),这适用于保留消息和非保留消息。

Q: 可以使用保留消息来进行 MQTT 的命令和控制吗?

A: 在某些情况下可以使用保留消息来进行命令和控制,但通常情况下使用非保留消息会更好。如果你需要确保命令消息即使在客户端暂时离线时也能被接收和处理,可以使用服务质量(QoS)级别 1 或 2,这可以确保消息的传递。

Q: 我能否获取 MQTT 代理中所有保留消息的列表?

A: MQTT 中的保留消息与主题相关联。当对某个主题进行新的订阅时,代理会在存在保留消息的情况下将该主题的保留消息发送给订阅者。但 MQTT 没有直接查询或列出所有保留消息或主题的标准功能。

Q: 当一个具有持久会话的客户端重新连接到代理时,保留消息会发生什么?

A: 当客户端带有持久会话重新连接到 MQTT 代理时,代理将根据其之前的订阅状态向客户端交付保留消息。

Q: MQTT 在间歇性网络连接时如何处理保留消息?

A: MQTT 在间歇性网络连接情况下通过在客户端重新连接到代理时,如果客户端对该保留消息关联的主题有活跃订阅,则将保留消息交付给客户端来处理。

Q: 当使用通配符订阅主题时,MQTT 是如何处理保留消息的传递的?

A: 当客户端使用通配符订阅主题时,代理会检查所有匹配的主题,对于每个包含保留消息的匹配主题,代理会将该消息发送给客户端。

Q: 我可以在 MQTT 中配置保留消息的大小限制吗?

A: MQTT 协议本身没有提供配置选项来限制保留消息的大小。然而,一些 MQTT 代理实现可能会提供这样的功能,你可以在其中设置保留消息的最大大小。

Q: MQTT 中保留消息的最大大小是多少?

A: MQTT 中保留消息的最大大小取决于您使用的具体 MQTT 代理实现。重要的是要考虑大型保留消息会对 MQTT 代理及其连接客户端的整体性能和资源利用率产生影响。

Q: MQTT 是如何处理保留消息的修改的?

A: 要修改保留消息,您需要发布一个具有相同主题和所需更新负载的新消息,并将“retain”标志设置为 true。然后,MQTT 代理将用新消息替换之前的保留消息。

Q: 我可以在 MQTT 中为保留消息设置过期时间吗?

A: 保留消息没有内置的机制来设置过期时间。你需要在应用层面处理它。在发布保留消息时,包括一个创建时间的 timestamp。

参考链接:

  1. https://www.hivemq.com/blog/mqtt-essentials-part-8-retained-messages/
  2. https://www.emqx.com/en/blog/mqtt5-features-retain-message
  3. https://cedalo.com/blog/mqtt-retained-messages-explained/
  4. http://www.steves-internet-guide.com/mqtt-retained-messages-example/
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-05-18,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • 什么是保留消息(Retained Messages)?
  • 在什么情况下使用 MQTT 保留消息?
  • 如何使用 MQTT 保留消息?
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档