什么事情都没有做,为什么MQTT设备频繁收到相同消息

什么事情都没有做,为什么MQTT设备频繁收到相同消息

什么事情都没有做,为什么MQTT设备频繁收到相同消息

    • 一、问题现象
    • 二、排查过程
    • 三、根因分析
      • 3.1 同主题 + Retain = true 导致死循环
      • 3.2 为什么指令类消息不能用 Retain
    • 四、Retain(保留消息)机制说明
      • 4.1 什么是 Retain
      • 4.2 Retain 使用策略
    • 五、修复建议
      • 5.1 主题分离
      • 5.2 Retain 配置调整
      • 5.3 配置检查项
    • 六、总结

一、问题现象

本人现在在做物联网智能设备开发,周末休息的时候,有客户使用产品,反馈 4G 开关产品存在以下异常:

  1. 设备一直在循环上报两条完整消息
Topic: /tianyi-up-smartswitch1-866597078379797 QoS: 0 { "imei": "866597078379797", "iccid": "89861125208093419149", "online": 1, "version": "1.0.10" } Topic: /tianyi-up-smartswitch1-866597078379797 QoS: 0 { "success": true, "message": "ok", "imei": "866597078379797", "source": "command", "commandName": "controller-restart", "messageId": "" }
  1. 上午下发软重启任务时,retain 默认成 true:客户当时未注意该配置,后发现此问题

二、排查过程

经逐步排查,从表象定位到根因:

排查步骤发现
初步分析设备循环上报在线状态和重启响应,消息重复收发
深入排查发现发布主题与订阅主题使用同一主题/tianyi-up-smartswitch1-866597078379797
进一步确认上午下发软重启指令时,retain默认设为true
根因定位设备收到指令后回包,回包又被自己收到,形成消息死循环

三、根因分析

3.1 同主题 + Retain = true 导致死循环

客户(平台) Broker 设备 │ │ │ │── retain=true ──"controller-restart"────────→│ │ │ 发布到 /tianyi-up-smartswitch1-... │──→ 设备收到重启指令 │ │ │ 执行重启,回包 │ │ │←──"success:true..."────────────│ │←────────────────────────────────────────────│ 发布到同一主题! │ │ │ │ │ 客户收到响应 │ │ │ (如果也做响应...) │ │ │── 再次回包 ─────────────────────────────────→│ │ │ ↓ 无限循环 │ │

核心问题

  1. 发布和订阅使用同一主题/tianyi-up-smartswitch1-866597078379797
  2. 指令下发时retain = true,回包也带retain = true
  3. 设备收到自己的回包,误认为是新指令,再次响应并上报

3.2 为什么指令类消息不能用 Retain

问题后果
指令重复执行设备断网重连后,再次执行旧指令(如再次重启)
时序混乱新旧指令混在一起,无法区分
安全风险"开/关"等指令被保留,意外触发后果严重
消息循环同主题下回包触发自我响应,无限循环上报

四、Retain(保留消息)机制说明

4.1 什么是 Retain

当发布消息时设置retain = true,Broker 会保存该主题的最后一条消息。之后任何新订阅者连接时,会立即收到这条保留消息,即使消息是在订阅之前发布的。

4.2 Retain 使用策略

消息类型Retain原因
控制指令(软重启、开/关、参数设置)false只执行一次,过期即失效
设备响应/回包false避免循环触发
设备状态(在线/离线)true新订阅者需要知道当前状态
配置信息(阈值、工作模式)true设备上线立即获取最新配置
遥测数据(温度、电量)false实时数据,保留旧值无意义

五、修复建议

5.1 主题分离

建议将收发分离为两个主题:

用途主题路径说明
平台下发指令/tianyi-up-smartswitch1-{imei}/cmd平台发布,设备订阅
设备上报响应/tianyi-up-smartswitch1-{imei}/ack设备发布,平台订阅
平台下发指令 ──→ /tianyi-up-smartswitch1-866597078379797/cmd ──→ 设备订阅收到 设备回响应 ──→ /tianyi-up-smartswitch1-866597078379797/ack ──→ 平台订阅收到 ↑ 互不干扰,无循环

主题分离后,即使同时订阅cmdack两个主题,也不会产生循环。因为设备回包只发到ack,不会发到cmd

5.2 Retain 配置调整

消息类型Retain 设置建议
平台下发指令(软重启、开/关)false发布时显式设置
设备响应/回包false设备端已默认

关键操作:发布任何控制指令时,显式设置retain = false

5.3 配置检查项

序号检查项优先级状态
1下发指令时retain显式设为false🔴 高
2发布主题与订阅主题分离(cmd / ack)🔴 高
3消息增加唯一 ID(messageId),支持业务层去重🟢 低

六、总结

客户最初反馈"设备一直循环上报两条数据",经排查根因是上午下发软重启指令时retain默认成true,且收发使用同一主题,导致设备回包被自身再次接收,形成消息死循环。建议通过主题分离及调整 retain 配置解决。