【问题标题】:MQTT 3.1.1 broker QoS=1 ("at least once") message redeliveryMQTT 3.1.1 代理 QoS=1(“至少一次”)消息重新传递
【发布时间】:2021-05-18 15:39:27
【问题描述】:

我正在尝试找出关于“至少一次”(QoS 1)配置的 MQTT 订阅者接收到的消息的 MQTT 3.1.1 消息重新传递的现实情况:

  • MQTT 代理是否会重新传递来自订阅者的未确认的“QoS 1”消息?
  • 必须经过多长时间才能重新交付 MQTT 代理?
  • MQTT 代理是否无休止地尝试重新传递未确认的消息?
  • 还有其他方法可以触发重新投递吗?

假设 MQTT 订阅者 没有用PUBACK 消息响应收到的 MQTT 消息,MQTT 代理需要(至少从我的理解)重新传递必须接收的消息“至少一次”,直到订阅者为该消息发送 PUBACK

为了更具体地了解我想要实现的目标:
推迟发送PUBACK 直到成功保留接收到的消息是一个好/有效的主意 - 有效地扩大 QoS 级别,直到我的订阅应用程序保证消息得到处理。
以及是否例如持久性错误(数据库超时)不会发送PUBACK,这将自动导致重新传递此类消息。

谢谢和最好的问候

【问题讨论】:

    标签: mqtt mosquitto hivemq mqtt-vernemq


    【解决方案1】:

    MQTT 代理是否会重新传递来自订阅者的未确认的“QoS 1”消息?

    来自[规范]:

    当客户端在 CleanSession 设置为 0 的情况下重新连接时,客户端和服务器都必须使用其原始数据包标识符 [MQTT-4.4.0-1] 重新发送任何未确认的 PUBLISH 数据包(其中 QoS > 0)和 PUBREL 数据包。这是唯一需要客户端或服务器重新传递消息的情况。

    所以,是的,未确认的 QOS1 消息将被重新传递,但规范要求发生这种情况的唯一时间是客户端重新连接时。

    虽然您明确指出您使用的是 MQTT v3.1.1,但我认为值得注意的是,MQTT v5 明确禁止除了重新连接之外的重新交付:

    当客户端重新连接并将 Clean Start 设置为 0 并且存在会话时,客户端和服务器都必须使用其原始数据包标识符重新发送任何未确认的 PUBLISH 数据包(其中 QoS > 0)和 PUBREL 数据包。这是唯一需要客户端或服务器重新发送消息的情况。客户端和服务器不得在任何其他时间重新发送消息

    必须经过多长时间才能重新交付 MQTT 代理?

    根据上述规范,不需要自动重试。一些经纪人可能会在一段时间后重新传输。 emqx 支持这个; mosquitto 曾经有一个选项,但在 1.5 版中已删除,change log 解释:。

    QoS>1 的传出消息在超时后不再重试。 当客户端重新连接时,将重试消息。这种行为变化 可以通过考虑何时可能发生超时来证明其合理性。

    • 如果连接不可靠且已断开,但没有一端 注意,这些消息将在重新连接时重试。发送 额外的 PUBLISH 或 PUBREL 不会改变任何东西。
    • 如果客户端过载/无法响应/连接速度较慢,则 发送额外的 PUBLISH 或 PUBREL 不会帮助客户抓住 向上。一旦积压已清除,客户端将响应。如果不是 能够赶上,发送额外的副本也无济于事

    MQTT 代理是否会无休止地尝试重新传递未确认的消息?

    3.11 规范未提供任何指导(因此,理论上是的),但许多代理对此提供了一些控制(排队的消息的最大数量、队列的最大大小等)。

    还有其他方法可以触发重新投递吗?

    是 - 断开并重新连接。

    推迟发送 PUBACK 直到接收到的消息被成功持久化是一个好/有效的主意

    paho-dev group a couple of months ago 上对此进行了讨论。 Go v5 Client 中正在考虑它的内容(当前客户端自动确认消息)。

    需要注意的一点是,MQTT 规范确实对order acknowledgments are sent 有要求。许多客户端忽略了这一要求(并且只在处理程序返回时发送确认),但有些(例如HiveMQ Java client)将 ACK 排队,以便它们可以按正确的顺序发送。

    【讨论】:

    • 感谢详细的答案。我猜根据 MQTT 规范,无法将 AMQP 0.9.1 或 AMQP 1.0 等其他消息传递协议的“确认”与 MQTT 的“确认”进行比较 - MQTT 似乎处理PUBACK,类似于 TCP 数据包 ACK。跨度>
    最近更新 更多