跳到主要内容
英文版本为准

本页译自英文,由模型翻译。若与英文原文存在差异,以英文原文为准。

结算

ack、drop、retry 和 retry_after 在 MQTT 上变成什么:QoS 1 和 2 下的一次确认,QoS 0 下什么也不发送,以及运行时发布的副本。

QoS 1 或 QoS 2 投递上处理器的每种结果:投递发送什么,以及随后发生什么处理器发送随后ack()PUBACKPUBREC完成drop()PUBACKPUBREC完成,消息被放弃retry()什么也不发送持久会话恢复时再次到来retry()有上限时PUBACKPUBREC立即发布一份副本retry_after(d)PUBACKPUBRECd 之后发布副本没有结果:被放弃的批什么也不发送同 retry():恢复时再次到来QoS 0 下什么也不发送:ack 和 drop 返回 AckError::Unsupported,运行时发布的副本照常发出
以文字阅读本图
  1. 处理器: ack(); drop(); retry(); retry() 有上限时; retry_after(d); 没有结果: 被放弃的批
  2. 发送: PUBACK PUBREC; PUBACK PUBREC; 什么也不发送; PUBACK PUBREC; PUBACK PUBREC; 什么也不发送; QoS 0 下什么也不发送:ack 和 drop 返回 AckError::Unsupported, 运行时发布的副本照常发出
  3. 随后: 完成; 完成, 消息 被放弃; 持久会话 恢复时 再次到来; 立即发布 一份副本; d 之后 发布副本; 同 retry(): 恢复时再次到来
  4. ack() → PUBACK PUBREC
  5. PUBACK PUBREC → 完成
  6. drop() → PUBACK PUBREC
  7. PUBACK PUBREC → 完成, 消息 被放弃
  8. retry() → 什么也不发送
  9. 什么也不发送 → 持久会话 恢复时 再次到来
  10. retry() 有上限时 → PUBACK PUBREC
  11. PUBACK PUBREC → 立即发布 一份副本
  12. retry_after(d) → PUBACK PUBREC
  13. PUBACK PUBREC → d 之后 发布副本
  14. 没有结果: 被放弃的批 → 什么也不发送
  15. 什么也不发送 → 同 retry(): 恢复时再次到来

MQTT 对一次投递只有一种应答,就是确认:QoS 1 下是 PUBACK,QoS 2 下是 PUBREC。ack 发送它。drop 也发送它,因为协议只允许服务以确认的方式结束一条消息。

MQTT 没有否定确认,所以服务器绝不会在当前连接上再次发送消息。没有任何声明的 retry() 返回 AckError::Unsupported,运行时把它记入日志,投递保持未确认。只有当持久会话在新连接上恢复时,服务器才会再次发送它。在此之前,它占用 Receive Maximum 窗口的一个槽位:一旦窗口被这样的投递占满,服务器在该连接上就不再发送 QoS 1 或 QoS 2 消息。处理器放弃的批同样保持未确认。

会话内的重试是运行时发布的一份副本。retry_after(d) 确认原消息,等待 d,然后发布一份副本。声明了上限或死信主题时,retry() 立即发布它的副本。QoS 0 投递没有可确认的东西,它的副本照样发出。

结果QoS 0
ack、dropAckError::Unsupported
retry()AckError::Unsupported;声明了上限时,立即发布一份副本
retry_after(d)在 d 之后发布一份副本
没有结果什么也不发生

重试​

MQTT 上的一次重试:按运行时的消息头计数的尝试上限,决定发布副本还是发往死信主题低于上限到达上限一个投递从 x-ruststream-retry-count 读取尝试次数处理器返回retry_after(d),或在有声明时返回 retry()max_attempts:这次尝试是否低于上限?原消息被确认,副本等待 dMqttTopic:副本发往它的主题MqttFilter:发往挂载点或转换指定的主题死信主题:投递发布到那里没有死信:确认并放弃副本就是一次发布:过滤器与其主题匹配的每个订阅都会收到它。等待延迟的副本保存在进程中,计时器触发前崩溃就会丢失它。
以文字阅读本图
  1. 低于上限: 原消息 被确认, 副本等待 d; MqttTopic: 副本发往 它的主题; MqttFilter: 发往挂载点 或转换 指定的主题
  2. 到达上限: 死信主题: 投递 发布到那里; 没有死信: 确认 并放弃
  3. 一个投递 从 x-ruststream-retry-count 读取尝试次数 → 处理器返回 retry_after(d),或在有声明时返回 retry(): 已处理
  4. 处理器返回 retry_after(d),或在有声明时返回 retry() → max_attempts:这次尝试是否低于上限?: 重试
  5. max_attempts:这次尝试是否低于上限? → 低于上限: 低于上限
  6. max_attempts:这次尝试是否低于上限? → 到达上限: 到达上限
  7. 副本就是一次发布:过滤器与其主题匹配的 每个订阅都会收到它。等待延迟的副本 保存在进程中,计时器触发前 崩溃就会丢失它。

上限在挂载点用 max_attempts 声明,第一次投递算作一次。MQTT 自己不统计投递次数,所以由运行时统计它发布的副本,次数记录在每份副本的 x-ruststream-retry-count 消息头中。

低于上限时,副本发往订阅形式的地址。MqttTopic 的地址是它自己的主题,共享的 MqttTopic 也是如此,因此它的注册无需指定任何东西。MqttFilter 匹配许多主题,却不能发布到其中任何一个,所以它的注册要指定副本发往的主题:可以只指定一次,也可以通过转换为每次投递指定。两者都没有指定的过滤器注册无法启动。

到达上限时,投递发往死信主题,载荷不变。没有声明死信主题时,投递被确认并放弃。

副本是一次普通的发布,因此它会到达过滤器与其主题匹配的每个订阅,本服务和其他服务中的订阅都包括在内。被某个活动过滤器匹配的死信主题会把消息直接送回来,所以死信主题应取一个没有订阅读取的名字。等待延迟的副本保存在进程中:正常关闭会等待它,计时器触发前崩溃则会丢失它。