持久会话上的 MQTT QoS 2 消息是否可以传送两次

问题描述 投票:0回答:1

我正在阅读有关 MQTT 消息顺序的两个 SO 问题和答案这里这里。所以基本上我们曾经相信 QoS 2 消息是按顺序传递的,并且只传递一次。这两个 SO 讨论纠正了这样的观点:在某些情况下,QoS 2 消息可能会无序传送,即如果它们位于不同的主题,或者第一次传送未正确确认时。

进一步思考,这里有一个问题:QoS 2 消息会被多次传递吗?

至少,考虑一个持久会话的情况:如果订阅者收到 PUBREL,则订阅者将传递消息并向发布者发送 PUBCOMP。订阅者将 PUBREL 和其他信息保存在内存中,因此如果 PUBCOMP 丢失,发布者将再次发送 PUBREL,或者从头开始重新发送消息,订阅者将知道它是同一消息的副本,并且不会两次传递相同的消息。

如果由于连接丢失导致 PUBREL 等信息丢失,如果订阅者内存中还有消息记录,则重连后同一条消息不会被投递两次。

但是如果订阅者丢失了记录,那么它将无法检测到重复记录。在后一种情况下,将再次传递相同的消息。到底是这样还是我的理解有误呢?是否存在其他情况会多次传递 QoS 2 消息?规范对此有何规定?各个实现在这方面是否有所不同?

enter image description here

mqtt
1个回答
0
投票

TLDR:QOS 2 =“仅一次交付”。然而,MQTT 要求保留会话状态,如果丢失,则保证不适用。

我将根据 MQTT V5 规范回答,因为您没有指定版本。 V3 和 V5 类似,但 V5 是一个较晚的规范,并且受益于 V3 部署中获得的经验。

QoS 2 消息是否会多次传送?

MQTT 规范声明 QOS2 =“仅一次交付”,因此您的问题的答案是“否”。然而,这假设符合规范,尤其是

客户端和服务器必须在会话的整个持续时间内存储会话状态 [MQTT-4.1.0-1]。

请注意,这是“必须”

必须:这个词,或者术语“REQUIRED”或“SHALL”,意味着该定义是规范的绝对要求。

因此会话状态的丢失违反了此条件,这意味着如果发生此类丢失,规范中所做的任何保证都将失效。规范作者意识到这一要求可能会被违反,并提供了“非规范评论/示例”来提供一些指导(基本上,您需要评估会话状态丢失对用例的影响,并采取适当的措施来保护状态)。 所以回答你的问题:

如果 PUBCOMP 丢失,发布者将再次发送 PUBREL,或者从头开始重新发送消息。

发件人的
规格

一旦发送了相应的 PUBREL 数据包,就不得重新发送 PUBLISH [MQTT-4.3.3-6]。

因此,您上面提到的“或从头开始重新发送消息”的情况将违反规范(当然,整个消息可以作为新消息重新发送,但 QOS 保证不适用于这种情况)。

但是如果订阅者丢失了记录,那么它将无法检测到重复记录

正如我在介绍中提到的,这将违反规范,因此 QOS 保证不再适用(并且消息可能会丢失/重复)。如果应用程序选择重新发送消息,则消息内容可能会被接收两次(但这超出了 MQTT 的范围)。

还需要注意的一点是 MQTT 规范涵盖了该协议。通常该协议将由库实现,并且设计库接口可能很棘手(您希望它简单/易于使用,但这可能会使某些边缘情况难以处理)。如果您确实关心消息传递,那么检查库源(并在适当的情况下将会话状态存储到磁盘)非常重要。

© www.soinside.com 2019 - 2024. All rights reserved.