从一道面试题说起:彻底搞懂 MQTT 的 QoS 等级

前言:MQTT 是物联网领域最常用的轻量级消息协议,而 QoS(Quality of Service,服务质量)机制是它区别于普通消息队列的核心设计之一。本文从一道常见的笔试题切入,讲清楚三个 QoS 等级的区别、QoS 2 的四次握手原理,顺便聊聊那些“报文名到底怎么读”的尴尬时刻。

一、先看一道题

MQTT QoS 2 的含义是?
A. 最多一次 B. 至少一次 C. 恰好一次 D. 不保证

答案是 C. 恰好一次(Exactly Once)。

MQTT 定义了三个 QoS 等级,这是一道送分题,但也是最容易混淆的知识点:

QoS 含义 机制 风险 系统开销
0 最多一次 发完就忘,不等确认 可能丢失 最小
1 至少一次 等确认,超时重发 可能重复 中等
2 恰好一次 四次握手 + 去重 不丢不重 最大

一个直觉记忆:保证越强,交互越多,开销越大。

二、三个等级分别是怎么工作的

QoS 0:最多一次

发送方把消息发出去就完事,不等待任何确认,也就是所谓的"Fire and Forget"。网络抖动、连接断开,消息就可能永远丢失。

适合场景:传感器周期性上报的温度、湿度数据——丢一条无所谓,下一条马上就来。

QoS 1:至少一次

发送方发出 PUBLISH 后会等待接收方的 PUBACK 确认。如果超时没收到,就重新发送。

问题在于:如果确认报文在路上丢了,发送方并不知道对方其实已经收到,重发就会导致消息重复。所以 QoS 1 只能保证“至少送达一次”,不保证“只送达一次”。

适合场景:告警通知、状态变更——宁可靠体重发,也不能漏报。

QoS 2:恰好一次

这是最高等级,通过两轮确认(四次握手)同时消除丢失和重复,下一节详细展开。

适合场景:计费、支付、指令下发等对精确性要求极高的场景。

三、QoS 2 的四次握手

QoS 2 的完整流程如下:

发送方                          接收方
  |------- PUBLISH (QoS2) ------->|
  |<---------- PUBREC ------------|   ← 第一轮:确认"收到了"
  |---------- PUBREL ------------>|
  |<---------- PUBCOMP -----------|   ← 第二轮:确认"处理完了"

四步可以口述为:

  1. 发布方发出 PUBLISH
  2. 接收方回复 PUBREC(我收到了)
  3. 发布方回复 PUBREL(可以释放了)
  4. 接收方回复 PUBCOMP(流程完成了)

为什么两轮握手就能消除重复?

关键在于接收方对 Packet ID(报文标识符) 的管理:

  • 接收方收到 PUBLISH 后,会先暂存该报文的 Packet ID,此时消息并不会交付给上层应用;
  • 在收到对应的 PUBREL 之前,如果发送方因超时重发了同一个 Packet ID 的 PUBLISH,接收方比对后发现是重复报文,会直接忽略,不再重复交付;
  • 直到收到 PUBREL,接收方才真正把消息投递出去并释放 Packet ID。

对比 QoS 1 就明白了:QoS 1 收到 PUBLISH 就立刻交付并回 ACK,重发自然造成重复;QoS 2 把“交付”这个动作推迟到流程走完,用 Packet ID 做了去重,所以能做到恰好一次。

代价是显而易见的:一次消息传递变成了四次报文往返,吞吐量下降、时延上升。这也是为什么实际项目中默认用 QoS 0 或 QoS 1,只有真正需要精确语义时才上 QoS 2。

四、彩蛋:PUBREC、PUBREL 到底怎么读?

面试或团队协作时,念错协议报文名多少有点尴尬。其实这些名字都是 PUBLISH + 关键单词缩写 拼出来的,整体连读即可:

报文 全称来源 读法 谐音参考
PUBACK PUBLISH ACKNOWLEDGMENT /pʌb-æk/ “帕布-艾克”
PUBREC PUBLISH RECEIVED /pʌb-rek/ “帕布-瑞克”
PUBREL PUBLISH RELEASE /pʌb-rel/ “帕布-瑞尔”
PUBCOMP PUBLISH COMPLETE /pʌb-kʌmp/ “帕布-康普”

发音要点:

  • PUB 统一读 /pʌb/(和 public 开头一样),不要逐字母拼 P-U-B;
  • PUBREC 结尾是 "rek",克音收尾;
  • PUBREL 结尾是 "rel",类似 real 的发音;
  • 行业习惯都是整体连读,直接说 "pub-rek"、"pub-rel" 大家都听得懂。

而且缩写本身就暗示了报文的作用,反过来帮助记忆握手流程:

  • PUBREC = Publish RECeived,“我收到了你的发布”
  • PUBREL = Publish RELease,“我释放了这个报文,流程可以结束了”

五、总结

回到开头的题目,核心考点就是区分三个 QoS 等级的语义:

  • QoS 0 → 最多一次:只发一次,可能不到
  • QoS 1 → 至少一次:没回音就重发,宁多勿少
  • QoS 2 → 恰好一次:两轮握手 + Packet ID 去重,不丢不重但开销最大

选择题里最容易踩的坑是混淆“至少一次”(QoS 1)和“恰好一次”(QoS 2)。记住 QoS 2 的本质——用 PUBREC/PUBREL/PUBCOMP 三种额外报文把“交付”这个动作卡在流程最后,用 Packet ID 挡住重复——这道题就再也不会做错了。

实际选型时的原则也很简单:按业务容忍度选等级,而不是盲目追求最高 QoS。可靠性是用性能换来的,够用就好。

THE END