MQTT QoS 0、1、2:如何选择正确的投递等级
文章
2026年7月24日
4 分钟阅读
UllrAI

MQTT QoS 0、1、2:如何选择正确的投递等级

根据消息丢失与重复的业务后果、网络行为和端到端处理方式选择 MQTT QoS,而不是默认数字越大越安全。

MQTTQoS可靠性物联网架构

MQTT Quality of Service 描述一条消息在客户端与 Broker 之间如何投递。它不是整个系统的“质量评分”,数字更高也不代表一定更适合。

正确的选择始于业务问题:如果消息丢失、重复、延迟或被处理两次,会发生什么?

QoS 作用于每一跳

发布侧与订阅侧的 QoS 独立协商。

发布者可以用 QoS 1 发送,而订阅者只请求 QoS 0。Broker 会按该订阅可用的较低等级投递。同样,QoS 2 也无法让数据库事务或物理执行器天然只执行一次,它只约束当前 MQTT 网络链路。

应分别分析完整路径:

设备 → Broker → 消费者 → 数据库或执行器

每个箭头和每个处理步骤都有不同的失败方式。

QoS 0:至多一次

QoS 0 发送 PUBLISH 后不等待确认。消息可能到达一次,也可能丢失。

它适合:

  • 高频数据;
  • 可由下一条新值替代;
  • 偶尔丢失成本很低;
  • 更看重低延迟和低开销。

例如每秒一次的温度、实时光标位置或高频调试指标。

QoS 0 并不等于“完全不可靠”。健康的 TCP 连接在保持连接时本身有顺序和可靠性。QoS 0 只是不会在连接中断后由 MQTT 继续恢复未完成的投递。

QoS 1:至少一次

QoS 1 要求接收 PUBACK。发布者未收到确认时可能重新发送,因此消费者必须允许重复消息。

QoS 1 很适合作为以下场景的默认起点:

  • 告警;
  • 状态变化;
  • 带幂等键的任务与指令;
  • 不希望出现缺口的测量;
  • 可以安全去重的事件。

载荷应支持幂等:

{
  "eventId": "01JZ8M7V2BR5H0R9BC2T2N2K0A",
  "deviceId": "pump-042",
  "type": "pressure.threshold.exceeded",
  "occurredAt": "2026-07-27T10:42:18Z",
  "value": 9.8,
  "unit": "bar"
}

消费者在执行副作用前记录 eventId。同一事件再次到达时,可以正常确认但不重复执行。

QoS 2:协议层恰好一次

QoS 2 使用四步交换:PUBLISHPUBRECPUBRELPUBCOMP。握手结束前,两端都要保存状态。

只有在以下条件成立时才值得承担这项成本:

  • 应用层很难安全处理重复;
  • Broker 和相关客户端都正确支持 QoS 2;
  • 已测量新增的延迟、带宽、内存和重连状态;
  • 确实需要 MQTT 当前链路的“恰好一次”。

QoS 2 仍无法让非事务副作用天然只执行一次。如果消费者启动电机后、保存完成状态前崩溃,MQTT 握手无法判断物理动作是否发生。业务幂等仍不可缺少。

MQTT QoS 对比:0、1 与 2

MQTT QoS 0 与 1 的主要取舍是恢复能力和开销。QoS 0 发送后不等待 MQTT 确认;QoS 1 会持续重试直到收到确认,因此消费者必须允许重复。消息丢失的影响大于重复到达时,应选择 QoS 1。

MQTT QoS 1 与 2 并不是“可靠”和“更可靠”的简单区别。QoS 1 使用两步报文交换并依赖应用幂等;QoS 2 使用四步协议握手,避免当前 MQTT 链路上的重复投递。QoS 2 仍无法让下游副作用恰好执行一次,因此多数生产系统使用 QoS 1 加事件 ID 或操作 ID,反而更简单也更完整。

下面的表格只能作为起点,最终选择还需在真实网络、消息速率、客户端库和 Broker 配置下验证。

消息建议起点原因
每秒传感器采样QoS 0下一条值可以替代丢失采样
设备在线状态QoS 1 + 保留消息状态重要,重复无害
告警事件QoS 1需要到达,可按事件 ID 去重
配置更新QoS 1 + 版本号只应用更新的版本
远程指令QoS 1 + 操作 ID + 过期时间避免过期与重复执行
财务或安全关键动作不应仅按表决定必须设计端到端事务与安全模型

QoS 与离线会话

根据 Broker 与会话设置,持久会话的订阅者离线时,QoS 1 或 2 消息可以排队。这很有用,但也可能在设备恢复后投递已经过时的工作。

指令消息应增加:

  • 消息过期时间;
  • 指令或操作 ID;
  • 目标设备身份;
  • 创建时间;
  • Schema 版本;
  • 确认主题或结果事件。

同时限制 Broker 队列。无限离线队列不是可靠性,而是没有边界的积压。

只应排队那些断线后仍有业务价值的消息。新的状态快照通常可以替代旧遥测,过期指令则应直接丢弃。需要同时测量单个客户端和整个设备群的重连积压,避免正常恢复过程压垮 Broker 或下游消费者。

测试失败,而不只是成功

有效的 QoS 测试应在关键时刻中断网络:

  1. 正常连接时发布;
  2. 确认返回前断线;
  3. 使用同一会话重连;
  4. 观察消息是否重试;
  5. 确认消费者正确处理重复;
  6. 确认过期指令不会执行。

还要测试大量客户端同时重连。单台设备很小的 QoS 状态,放大到设备群后可能非常可观。

推荐默认策略

高频、可替代的遥测从 QoS 0 开始;重要事件与指令从 QoS 1 开始。在考虑 QoS 2 前,先把消费者幂等做好。

要了解完整协议模型,请阅读 MQTT 协议概览。使用主题设计指南明确权限与消息含义,并在生产设备启用持久会话前检查 MQTT 安全指南MQTT 教程提供了可直接执行的发布与订阅命令。

把 MQTT 指南用于实践

先用一次性数据验证发布订阅链路,再跟随完整教程继续实践。