3. MQTT QoS等级深度解析:从原理到实战选型

MQTT 的 QoS(Quality of Service,服务质量)是很多初学者容易忽略、但在实际项目中又极其关键的概念。说白了,它就是决定消息「能不能送到」、「能送到几次」的规则。

我刚开始用 MQTT 时,觉得 QoS 0 就够用了,结果在做一个温湿度采集项目时,数据丢得我怀疑人生。后来才明白——选错 QoS,轻则丢数据,重则系统崩溃。今天咱们就把 QoS 0、1、2 这三个等级彻底讲透。

3.1 三个等级,三种承诺

MQTT 定义了三个 QoS 等级。每个等级对应不同的消息送达保证,也对应不同的网络开销。我习惯用一个比喻来理解:

  • QoS 0 —— 发完就走,不管收没收到。像扔纸飞机。
  • QoS 1 —— 至少送到一次,但可能重复。像快递员敲门,没人应就再敲。
  • QoS 2 —— 确保恰好一次,不多不少。像签收快递,还要你签字确认。

下面这张图能帮你快速建立整体认知:

MQTT QoS 等级对比图 MQTT QoS 等级对比 QoS 0 至多一次 发布者 → 代理 无确认 无存储 无重传 🔥 最快 ❌ 可能丢消息 QoS 1 至少一次 发布者 → 代理 PUBACK 确认 代理持久存储 超时重传 ⚡ 较快 ⚠️ 可能重复 QoS 2 恰好一次 发布者 ↔ 代理 四次握手 PUBREC/PUBREL/PUBCOMP 严格去重 🐢 最慢 ✅ 最可靠 QoS 等级越高,可靠性越强,但网络开销和延迟也越大

3.2 QoS 0:至多一次(Fire and Forget)

这是最基础的等级。发布者把消息扔给 Broker,然后就不管了。Broker 也不会回复任何确认。说白了,消息可能到,也可能不到——全看网络心情。

适用场景:

  • 传感器高频数据上报(如温度每 5 秒一次,丢一两个无所谓)
  • 日志输出、调试信息
  • 非关键的状态指示(如 LED 闪烁模式)
我的经验: 在 ESP32 上做传感器采集时,如果数据变化不快(比如室温),我习惯用 QoS 0。因为即使丢一包,下一包 5 秒后就来了,系统完全能接受。但如果是控制指令——千万别用 QoS 0,你会后悔的。

3.3 QoS 1:至少一次(At Least Once)

QoS 1 会保证消息至少被送达一次。流程是这样的:

  1. 发布者发送 PUBLISH 包给 Broker
  2. Broker 收到后,回复 PUBACK 确认包
  3. 如果发布者没收到 PUBACK,会在超时后重发

这里有个坑:消息可能重复。因为发布者重发时,Broker 可能已经收到并处理了第一次的消息,只是 PUBACK 在路上丢了。结果就是 Broker 收到两次相同的消息。

我曾经踩过的坑: 做一个智能灯控项目,用 QoS 1 下发「开灯」指令。结果网络抖动,指令被重复执行了两次——灯开了又关。用户投诉说「你们的灯有毛病」。从那以后,凡是控制类指令,我都不敢只用 QoS 1。

适用场景:

  • 需要确保送达,但能容忍重复的消息
  • 数据本身有去重机制(如带时间戳或序列号)
  • 遥测数据上报(如电量、信号强度)

3.4 QoS 2:恰好一次(Exactly Once)

QoS 2 是 MQTT 最可靠的等级。它通过四次握手来确保消息既不丢失、也不重复。流程如下:

  1. PUBLISH:发布者发送消息给 Broker
  2. PUBREC:Broker 回复「已收到,但别发重复的」
  3. PUBREL:发布者回复「确认,你可以释放了」
  4. PUBCOMP:Broker 回复「已完成」

你想想看,这四次交互下来,网络开销是 QoS 0 的 4 倍以上。但换来的是——消息绝对不丢、绝对不重复。

适用场景:

  • 支付指令、计费数据
  • 设备固件升级指令
  • 关键控制命令(如阀门开关、门锁控制)
  • 需要审计追踪的数据
核心原则: 只有当你「既不能丢消息,也不能重复处理消息」时,才用 QoS 2。否则,QoS 1 通常就够用了。

3.5 QoS 选择策略与性能权衡

选 QoS 不是拍脑袋的事。我一般从三个维度来权衡:

维度 QoS 0 QoS 1 QoS 2
网络开销 1 个包 2 个包 4 个包
延迟 最低 中等 最高
CPU 占用 几乎为零 低 高(需维护状态机)
内存占用 无 需缓存未确认消息 需维护四次握手状态
可靠性 低 中(可能重复) 高

在 ESP32 这种资源受限的设备上,这个权衡尤其明显。我记得有一次在 ESP32 上用 QoS 2 同时处理 50 个主题,结果内存直接爆了——因为每个 QoS 2 消息都需要维护一个状态机。

3.6 实际项目中的 QoS 选型建议

说了这么多理论,咱们直接上实战建议。这是我多年项目经验的总结:

我的选型口诀:
「传感器数据用 QoS 0,控制指令用 QoS 1 加去重,关键命令用 QoS 2。」

具体场景建议:

  • 环境监测(温湿度、光照):QoS 0。数据量大、变化慢,丢几包不影响。
  • 设备心跳/在线状态:QoS 1。需要确保服务器知道设备在线,重复一两次无所谓。
  • 远程控制(开关、调节):QoS 1 + 应用层去重。比如每条指令带唯一 ID,设备端做幂等处理。
  • 固件升级指令:QoS 2。这个绝对不能丢,也不能重复触发升级流程。
  • 报警/告警信息:QoS 1 或 QoS 2。取决于告警的严重程度——火灾告警我肯定用 QoS 2。
  • 日志批量上传:QoS 0。丢了就丢了,反正本地还有缓存。
重要提醒: QoS 是端到端的。发布者和订阅者的 QoS 等级可以不同。Broker 会以两者中较高的等级来转发消息。比如发布者用 QoS 0,但订阅者要求 QoS 2——Broker 会按 QoS 2 转发给该订阅者。但发布者到 Broker 这一段仍然是 QoS 0,所以消息可能在第一步就丢了。

最后说一句:不要为了「保险」就无脑上 QoS 2。在 ESP32 上,QoS 2 的内存开销和延迟可能会让你的系统变得非常迟钝。我见过一个项目,所有消息都用 QoS 2,结果 ESP32 频繁重启——就是因为内存碎片化太严重了。

选 QoS,本质上是在「可靠性」和「资源消耗」之间找平衡。理解了这个,你就能做出合理的选择。