跳转到内容

QoS 对比与选择

本节对比 MQTT 三种 QoS 级别的特性差异,提供实用的选择指南。学习完成后,您将能够:

  • 快速根据不同场景选择合适的 QoS 级别
  • 清晰解释三种 QoS 级别的区别
  • 设计合理的 QoS 使用策略
  • 避免 QoS 使用中的常见错误

在开始本节之前,请确保:

  • 理解 QoS 0、1、2 的各自原理
  • 了解不同 IoT 场景的可靠性需求
QoS 0: At Most Once (最多一次)
┌─────┐ ┌─────┐
│ Pub │────────→│ Broker │ ✗ 无确认
└─────┘ └─────┘ ✗ 无重试
快速 ⚡ 不可靠 ⚠️
QoS 1: At Least Once (至少一次)
┌─────┐ ┌─────┐
│ Pub │────────→│ Broker│ ✓ PUBACK 确认
└─────┘←───✓───└─────┘ ✓ 超时重试
可靠 ✅ 可能重复 ⚠️
QoS 2: Exactly Once (恰好一次)
┌─────┐ ┌─────┐
│ Pub │──①──→│ Broker│ ① PUBLISH
└─────┘←──②───└─────┘ ② PUBREC
│ ──③──→ ③ PUBREL
│ ←──④─── ④ PUBCOMP
最可靠 🛡️ 最慢 🐢
因素QoS 0QoS 1QoS 2
消息丢失可能几乎不绝不
消息重复绝不可能绝不
网络开销最低最高
延迟影响最快最慢
资源消耗最低最高
实现复杂度最简单最复杂
这个场景可以接受偶尔的消息丢失吗?
├── 是 → 使用 QoS 0
│ 例:温度传感器(每 3 秒更新一次)
│ 光照传感器
│ 调试日志
└── 否 → 消息重复会造成问题吗?
├── 否 → 使用 QoS 1
│ 例:开关灯命令(重复开灯没问题)
│ 告警通知
│ 状态更新
└── 是 → 使用 QoS 2
例:支付交易
库存计数(重复=错误)
计费数据
关键安防告警
场景推荐 QoS理由
DHT22 温度数据(3 秒间隔)QoS 0丢失一次不重要,下次更新即可
开关灯控制命令QoS 1重复开灯不影响,但不能丢失
火警告警QoS 2不能丢失也不能重复(避免误报)
Shelly 插座状态QoS 1重复状态可接受
工单按钮触发QoS 1必须触发,重复触发可清理
固件版本查询QoS 1需要可靠的查询-应答
支付确认QoS 2必须精确一次

根据消息发送频率选择合适的 QoS:

频率 > 1 Hz (每秒多次)
→ 推荐 QoS 0
→ 例:加速度计数据、振动分析
→ 理由:丢失个别采样点不影响整体
频率 0.1 - 1 Hz (每 1-10 秒)
→ 推荐 QoS 0 或 QoS 1
→ 例:温度、湿度、光照
→ 理由:根据数据重要性选择
频率 < 0.1 Hz (每 10 秒以上)
→ 推荐 QoS 1 或 QoS 2
→ 例:控制命令、告警、配置更新
→ 理由:低频消息通常更重要
// 不同类型数据的 QoS 选择
void publishSensorData() {
// 1. 高频环境数据 → QoS 0
mqttClient.publish("sensors/temperature", "26.5");
// 2. 设备状态变化 → QoS 1
publishStatus("devices/status", "online", 1);
// 3. 告警事件 → QoS 1 或 2
publishAlert("alarm/fire", "Zone A - Fire detected", 2);
}
// 注意:PubSubClient 仅支持 QoS 0
// 如需 QoS 1/2,使用 AsyncMqttClient 或其他库
// Node-RED 中的 QoS 策略
// 不同类型的节点配置不同的 QoS
// MQTT In 节点配置矩阵:
// 传感器数据 → QoS 0
// 设备状态 → QoS 1
// 关键告警 → QoS 2
// Function 节点:动态设置 QoS
msg.qos = determineQoS(msg.topic);
return msg;
function determineQoS(topic) {
if (topic.startsWith("sensors/")) return 0;
if (topic.startsWith("alarm/")) return 2;
return 1; // 默认使用 QoS 1
}

为整个系统制定统一的 QoS 策略:

QoS 分配策略示例:
┌───────────────────────────────────────────┐
│ QoS 0 (最大流量,最小开销) │
│ ├── sensors/# 传感器数据 │
│ ├── telemetry/# 遥测数据 │
│ └── logs/# 日志消息 │
├───────────────────────────────────────────┤
│ QoS 1 (可靠投递,可重复) │
│ ├── devices/+/status 设备状态 │
│ ├── devices/+/set 控制命令 │
│ ├── alarm/notification 告警通知 │
│ └── config/# 配置更新 │
├───────────────────────────────────────────┤
│ QoS 2 (精确投递,不重不漏) │
│ ├── critical/alarm 关键告警 │
│ ├── payment/# 支付交易 │
│ └── inventory/# 库存操作 │
└───────────────────────────────────────────┘
# mosquitto.conf - QoS 相关配置
# 设置入站消息的 QoS 上限
# inbound QoS limit reduces QoS for all incoming messages
max_qos 2 # 默认允许所有 QoS 级别,可根据需要降低
# 限制排队消息数量
max_queued_messages 1000 # 超出丢弃
# 持久化 QoS 1/2 消息
persistence true
persistence_location /mosquitto/data/
QoS100 msg/s 延迟1000 msg/s 延迟CPU 使用率
00.3ms0.8ms8%
11.2ms4.5ms25%
23.5ms18ms55%
QoS 0:
成本: 最低
收益: 最高性能
适用: 85% 的 IoT 场景
QoS 1:
成本: 中等(3x 网络流量)
收益: 可靠投递
适用: 13% 的场景
QoS 2:
成本: 高(10x 网络流量)
收益: 无重复保证
适用: 2% 的关键场景

Q1: 我应该为所有消息使用 QoS 2 吗?

Section titled “Q1: 我应该为所有消息使用 QoS 2 吗?”

A: 不建议。QoS 2 的资源消耗约为 QoS 0 的 10 倍。对于每 3 秒更新一次的传感器数据,丢失一次完全没有影响。只需为控制命令、告警等关键消息选择更高的 QoS。

Q2: QoS 0 的消息会不会全部丢失?

Section titled “Q2: QoS 0 的消息会不会全部丢失?”

A: 不会。MQTT 运行在 TCP 协议之上,TCP 本身已经保证了连接的可靠性。QoS 0 的消息丢失通常只发生在 Broker 崩溃或网络完全断开时。在正常运行的网络中,QoS 0 的消息投递率超过 99.9%。

A: 根据两个问题决定:

  1. 消息丢失有影响吗?→ 无影响用 QoS 0
  2. 消息重复有问题吗?→ 没问题用 QoS 1,有问题用 QoS 2

本节要点总结:

  1. QoS 0:最快最轻量,适合高频传感器数据(85% 场景)
  2. QoS 1:可靠可重复,适合控制命令和通知(13% 场景)
  3. QoS 2:最可靠最昂贵,适合关键业务操作(2% 场景)
  4. 选择策略:根据”丢失影响”和”重复影响”两个维度判断
  5. 系统级规划:为不同 Topic 层级统一规划 QoS 策略