3、QoS 1详解:至少一次送达、工作原理、DUP标志与消息去重

好,咱们接着聊QoS 1。说实话,QoS 1是我在实际项目里用得最多的一个等级。为什么?因为它性价比高啊——比QoS 0可靠,又没QoS 2那么重。说白了,它就是「至少一次送达」的保证。

你想想看,在物联网场景里,大部分数据丢一条问题不大,但绝对不能丢太多。比如传感器上报的温度数据,偶尔丢一条没关系,但要是连续丢好几条,那控制逻辑可能就出问题了。QoS 1正好卡在这个平衡点上。

3.1 什么是「至少一次送达」?

字面意思:消息至少会被送达一次。但注意,它没说「只送一次」。实际上,QoS 1的消息可能会被重复投递。我在项目中遇到过,同一个设备状态更新,客户端收到了两次一模一样的消息。嗯,这就是QoS 1的特性。

核心要点就两个:

  • 保证送达:只要网络没彻底断掉,消息最终能到
  • 可能重复:因为重传机制,接收方可能收到多份

重要概念:QoS 1不保证「不重复」,只保证「不丢失」。如果你的业务逻辑对重复数据敏感,那必须在应用层做去重处理。

3.2 工作原理:一次完整的QoS 1对话

咱们来看一个典型的QoS 1消息流转过程。假设Publisher要发一条消息给Broker:

Publisher                    Broker
    |                          |
    |--- PUBLISH (QoS=1) ---->|
    |                          |
    |<--- PUBACK ------------|
    |                          |

流程很简单:

  1. Publisher发送PUBLISH报文,QoS字段设为1
  2. Broker收到后,立即回复一个PUBACK报文
  3. Publisher收到PUBACK,确认消息已送达,删除本地缓存

这里有个关键点:Publisher在收到PUBACK之前,必须保留这条消息。为什么?因为如果没收到ACK,它要重发。我见过不少新手踩这个坑——发完消息就丢,结果重传时拿不到原始数据。

3.3 DUP标志:重传的身份证

DUP标志,全称是Duplicate。它告诉接收方:「嘿,这条消息你可能已经见过了。」

具体规则:

  • 第一次发送时,DUP = 0
  • 如果重传,DUP = 1
  • 接收方看到DUP=1,就知道这是重发的消息

但注意,DUP标志只是一个提示,不是绝对的。我曾经调试过一个诡异的问题:客户端收到了DUP=1的消息,但之前根本没收到过原始消息。这正常吗?嗯,其实是正常的。因为DUP标志只表示「发送方重传了」,不代表「接收方一定收过」。可能之前的原始消息在网络中丢了,接收方压根没见过。

我的建议:不要完全依赖DUP标志做去重。它更多是给调试和日志分析用的。真正的去重,要靠消息ID(Packet Identifier)。

3.4 消息去重:谁来负责?

这个问题很关键。QoS 1本身不提供去重机制,那重复的消息谁来处理?

答案是:应用层自己负责

常用的去重策略有几种:

策略 实现方式 适用场景
幂等处理 同样的消息处理多次,结果一样 状态更新、开关控制
消息ID去重 记录已处理的消息ID,重复则丢弃 命令下发、支付通知
时间戳去重 比较消息时间戳,只处理最新的 传感器数据、位置上报

我个人习惯用「幂等处理+消息ID去重」的组合。比如在智能家居项目里,控制灯的开关命令,我让设备端记录最近100个已处理的Packet Identifier。收到重复的,直接忽略。这样既简单又可靠。

3.5 避坑指南:QoS 1的常见陷阱

做QoS 1开发,有几个坑我帮你们踩过了:

我曾经在一个车联网项目里,用QoS 1上报GPS数据。结果发现服务器端收到了大量重复的位置点。排查了半天,发现是客户端重传超时设得太短,导致频繁重传。后来把重传间隔从1秒改成5秒,问题就解决了。

其他常见问题:

  • PUBACK丢失:如果PUBACK在网络中丢了,Publisher会重传。但Broker已经处理过消息了,所以会再次回复PUBACK。这时候Publisher收到第二个PUBACK,直接忽略就行。
  • 消息积压:如果网络不好,Publisher会积压大量待确认的消息。MQTT协议规定,客户端可以同时发送多条未确认的QoS 1消息,但数量受限于接收窗口。我建议把并发数控制在10以内,否则内存容易爆。
  • Session过期:如果客户端断线重连,但之前的Session已经过期,那所有未确认的QoS 1消息都会丢失。嗯,这个坑我踩过两次才记住。

3.6 实战建议:什么时候用QoS 1?

根据我的经验,以下场景适合用QoS 1:

  • 传感器数据上报:温度、湿度、电量等,丢一两条不影响整体趋势
  • 设备心跳:告诉服务器「我还活着」,偶尔丢一次没关系
  • 日志上传:非关键日志,允许少量丢失
  • 状态同步:设备状态变化通知,重复了也没事,反正状态是幂等的

不适合的场景:

  • 支付指令:绝对不能重复,必须用QoS 2
  • 控制命令:比如「打开阀门」,重复执行可能出事故
  • 计费数据:重复会导致多扣钱,必须精确一次

一句话总结:QoS 1是物联网的「万金油」。它不完美,但够用。只要你的业务能容忍偶尔的重复,QoS 1就是性价比最高的选择。

好了,QoS 1就聊到这儿。下一节咱们讲QoS 2,那个才是真正的「精确一次送达」,但代价也大得多。到时候我给你们讲讲我在金融项目里用QoS 2的血泪史。