为什么 MQTT 的 Last Will Testament 对生产物联网不足(以及我们改而构建的方案)

发布: (2026年2月22日 GMT+8 14:10)
3 分钟阅读
原文: Dev.to

Source: Dev.to

我花了 7 年时间构建云后端——但当我尝试连接真实硬件(我家里的 ESP32)时,遇到了瓶颈:

“我的设备在 AWS IoT Core 上显示‘已连接’……但已经 4 小时没有上报数据了。是卡住了?死机了?还是只是离线了?”

结果是:MQTT 的遗嘱(LWT)在骗你。

谎言:“已连接” ≠ 活着

LWT 只在 TCP 断开 时触发。真实设备可能会静默失效:

  • Wi‑Fi 断开但 TCP 套接字仍保持打开(NAT 超时 = 5 + 分钟)
  • 设备卡死但没有重启(看门狗失效)
  • 传感器循环崩溃,而 MQTT 客户端仍报告“已连接”

结果?你的仪表盘显示 ✅ 在线,但设备自昨天起就没有发送任何数据。

AWS IoT Core 显示已连接但数据陈旧的设备

我们的解决方案:应用层心跳 + 有状态 ACK

我们构建了一个轻量级 Spring Boot 后端(hear‑beat),把 遥测视为心跳脉冲——而不仅仅是数据。

Device → [temp=28°C, ts=1708512000] → Backend
Backend → "ACK @ 1708512000" → Device

离线检测 = 心跳窗口错过

// DeviceRegistry.java
if (System.currentTimeMillis() - lastHeartbeat > OFFLINE_THRESHOLD) {
    markDeviceOffline(deviceId); // 不是 TCP 断开 —— 实际沉默
}

通过 ACK 循环保证指令安全

// CommandService.java
sendCommand(deviceId, "REBOOT");
waitForAck(deviceId, timeout = 30_000); // 它真的*执行*了吗?而不是仅仅“收到”

REST 控制平面 + MQTT 数据平面

  • 移动端使用 REST (POST /devices/{id}/command)
  • 设备使用 MQTT (iot/device/{id}/cmd)
  • 后端桥接两者 → 清晰的职责分离

为什么这对真实部署很重要

场景LWT 结果我们的心跳结果
设备卡死(未重启)✅ 已连接❌ 离线(90 秒内无心跳)
农田中的 Wi‑Fi 断开✅ 已连接(TCP 仍存活)❌ 离线(2 分钟内无数据)
发送指令但设备在执行过程中崩溃✅ 指令已送达❌ 无 ACK → 重试/安全失效

这不是理论。我在家里的传感器上使用它——它每天都能捕捉到 LWT 漏掉的故障。

亲自尝试

git clone https://github.com/AnilSaithana/hear-beat
cd hear-beat
docker-compose up   # 运行 Spring Boot + MQTT broker

ESP32 固件示例位于 /firmware 文件夹中。

我之所以构建它,是因为生产环境的 IoT 在云端与硬件之间的空隙中经常失效。

0 浏览
Back to Blog

相关文章

阅读更多 »