尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

自动售货机MQTT通信踩坑实录:从掉线丢消息到百万级设备稳定在线的进化之路~YH

自动售货机MQTT通信踩坑实录:从掉线丢消息到百万级设备稳定在线的进化之路~YH MQTT是物联网的事实标准自动售货机也不例外。但把MQTT跑稳尤其是在工业环境下跑稳比想象中难得多。一、协议选型为什么是MQTT不是HTTP做设备通信方案设计的时候第一个问题就是用HTTP还是MQTTHTTP的优点是简单谁都会用。缺点也很明显轮询效率低、实时性差、服务器压力大。每台设备每隔几秒就轮询一次一万台设备就是每秒几千次请求服务器扛不住。MQTT的优势长连接、实时推送、协议轻量、支持大规模并发。一台MQTT服务器可以扛几万到几十万台设备。消息是实时推送的不需要轮询。所以在售货机场景下MQTT是唯一合理的选择。二、QoS级别怎么选这是一个哲学问题MQTT有三个QoS级别。我们花了两周时间在这上面纠结。QoS 0最多分发一次。消息可能丢但开销最小。QoS 1至少分发一次。消息不丢但可能重复。QoS 2正好一次。消息不丢不重复但开销最大。我们的选择大部分消息用QoS 1支付相关用QoS 2心跳用QoS 0。开门指令、支付结果这类消息不能丢用QoS 1确保送达。重复消费虽然麻烦但可以幂等处理。心跳丢了无所谓下一个心跳周期会补上。支付相关的关键指令用QoS 2——虽然开销大但出错代价更高。坑点提醒QoS 2在大规模场景下性能下降明显。如果设备数量超过5万台QoS 2的吞吐量可能成为瓶颈。此时需要在QoS 1 应用层去重和QoS 2之间做权衡。三、心跳间隔设多少30秒是经验值心跳太频繁服务器压力大设备耗电。心跳间隔太长断线检测不及时。我们经过压测得出的结论心跳间隔30秒是最优值。设备每30秒发一次PINGREQ。服务器在1.5倍心跳间隔45秒内没收到心跳判定设备离线。但不断开连接再等1.5倍间隔90秒还没收到彻底断开并触发遗嘱消息。实测数据30秒心跳间隔下单台服务器能稳定支撑2.8万到3.2万台设备。超出这个数量需要做集群。四、遗嘱消息设备死了要让服务器知道这是MQTT最被低估的功能但在售货机场景里超级有用。设备连接时设置遗嘱消息Last Will——如果我异常断线了把这个消息发到指定Topic。服务器收到后可以立即知道哪台设备离线了触发告警。我们利用遗嘱消息实现了设备异常离线告警——运维团队会在5秒内收到钉钉通知比用户发现机器黑屏快了至少10分钟。五、消息持久化断网期间的消息不能丢这是生产环境最大的坑。设备断网期间云端下发的指令改价、调温、远程开门如果设备收不到会造成很严重的问题。我们的方案云端消息下发时先存入数据库状态标记为未送达。设备上线后云端检查所有未送达消息批量推送给设备。设备端收到消息后回复ACK确认。云端收到ACK后将消息状态更新为已送达。消息有效期超过24小时未送达的消息自动失效运维人员会收到通知手动处理。这个机制保证了一台设备断网一周后重新上线期间的所有指令都能被正确执行。六、Topic设计分得越细越好Topic设计决定了消息路由的灵活性和系统扩展性。我们的Topic分层vending/{deviceId}/state/online - 设备上线通知vending/{deviceId}/state/heartbeat - 设备心跳vending/{deviceId}/command/price/update - 云端下发改价指令vending/{deviceId}/command/temperature/set - 云端下发调温指令vending/{deviceId}/event/order/paid - 设备上报支付成功vending/{deviceId}/event/error - 设备上报故障这种设计的好处运维人员可以订阅特定设备的特定事件数据分析系统可以只订阅event/order相关Topic云端可以批量下发指令。七、性能压测数据这是我们压测的最终数据供参考指标数值单服务器最大设备连接数3.2万台消息吞吐量QoS 18600条/秒消息吞吐量QoS 22100条/秒平均消息延迟120ms99.9%消息延迟380ms系统可用性99.97%八、总结MQTT看起来很轻量但要把生产环境的稳定性做好需要从QoS、心跳、遗嘱、持久化、Topic设计等多个维度去优化。最核心的一条经验MQTT不是搭起来就能用的基础设施它需要根据业务场景做大量配置和二次开发才能支撑百万级设备的稳定在线。
返回列表