MQTT的保留消息可以为订阅者提供指定主题上的最新状态(前提是最新消息发布时保留标志设置为true)。

保留消息是保留标志设置为true的普通MQTT消息

每个订阅带有保留消息的主题的客户端在订阅后都会立即接收保留消息

当客户端向指定主题发送多条保留消息时,代理仅存储最后的保留消息以及相应的QoS级别。

代理为每个主题仅存储一条保留消息

保留消息

保留消息流程示意图如下:

存在问题

在MQTT采用的发布/订阅模式中,消息的发布者与订阅在很大程度上解耦,发布者无法保证订阅者能够收到某条消息。

发布者的责任在于确保消息可靠地传递给代理。类似地,订阅者无法确定发布者何时发送与其订阅主题相关的新消息

如果消息之间的时间间隔相差很大,从几秒到几分钟甚至几小时不等,那么订阅者在发布者发布新消息之前始终不知道当前主题状态

解决方案

针对于上述问题,MQTT协议通过支持保留消息来解决。

具体实现步骤如下:

  1. 发布者发布一条保留标志为true的消息给代理。
  2. 代理收到该消息并存储。
  3. 新订阅该保留消息对应主题的订阅者会收到该保留消息。

注意:保留消息发布时,如果订阅者在线并订阅了对应主题,那么此时收到的并非保留消息。只有订阅者重新订阅主题(设备掉线、手动取消再次订阅)才会收到保留消息

从本质上讲,保留消息为订阅者提供了该主题的最后已知状态的快照,确保无论发布频率如何,都可以访问最新的相关信息。

保留消息存储的是指定主题的保留标志为true的最新消息,但不一定是该主题上的最新消息。因为可能在最新保留消息之后发布过其他非保留消息。

保留消息发布与清除

发布

发送保留消息的方式是将发送的普通消息的保留标志设置为true即可

该标志用于通知代理以保留消息并将其提供给订阅者。

删除

删除保留消息仅有一种方法,即发送零字节负载的保留消息到对应的主题上

当MQTT代理收到该保留消息主题上的负载为空时,则会将其视为删除请求,并立即删除与该主题相关的保留消息。新的订阅者将不再收到该主题之前的保留的消息。

在很多情况下,根本没有必要显式删除保留消息,这是因为每条新的保留消息都会自动覆盖同一主题的前一条保留消息

这种方式可确保订阅者收到最新的相关信息。

使用场景

发布/订阅模式虽然能让消息的发布者与订阅者充分解耦,但存在一个缺点,即订阅者无法主动向发布者请求消息

订阅者何时收到消息完全依赖于发布者何时发布消息,这在某些场景中就产生了不便。

然而MQTT保留消息解决了这一难题,即当发布者启用保留标志发布消息时,MQTT代理则会存储该消息,此时新连接的订阅者订阅相应主题时就会立即收到消息,而无需等待发布者发布下一条消息

借助于保留消息,新的订阅者能够立即获取最近的状态,而不需要等待无法预期的时间。下面是一些示例:

  • 智能家居设备的状态只有在变更时才会上报,但是控制端需要在上线后就能获取到设备的状态;
  • 传感器上报数据的间隔太长,但是订阅者需要在订阅后立即获取到最新的数据;
  • 传感器的版本号、序列号等不会经常变更的属性,可在上线后发布一条保留消息告知后续的所有订阅者;