3、MQTT基础回顾:MQTT协议原理、QoS等级详解、主题(Topic)与通配符、保留消息与遗嘱消息

3.1 MQTT协议原理:轻量级的“快递员”

MQTT,全称是Message Queuing Telemetry Transport。名字挺长,但说白了,它就是个轻量级的发布/订阅消息协议。

我经常跟团队里的年轻人打比方:MQTT就像一个快递员。你(发布者)把包裹(消息)交给快递站(Broker),快递站再根据包裹上的地址(主题),派送给收件人(订阅者)。整个过程,你不需要知道收件人是谁,收件人也不需要知道你是谁。这就是解耦。

为什么工业物联网里它这么火?因为它的协议头非常小,最小只有2个字节。你想想看,在那些动不动就丢包、带宽窄得像羊肠小道的工业现场,这简直是救星。我曾在一条老旧的RS485线路上跑MQTT,硬是把数据给传回来了,换HTTP?想都别想。

MQTT的核心角色有三个:

  • 发布者(Publisher):产生数据的设备,比如PLC、传感器。
  • 代理服务器(Broker):消息中转站,负责接收和分发。这是整个系统的核心。
  • 订阅者(Subscriber):消费数据的应用,比如SCADA、MES、数据库。

整个通信流程就是:发布者发消息到Broker的一个主题,Broker再把这个消息推送给所有订阅了这个主题的订阅者。简单、高效、解耦。

我的经验: 选Broker时,别只看功能。我踩过坑,某个开源Broker在500个客户端同时重连时直接崩溃。生产环境,建议用EMQX或Mosquitto,稳定性经过验证。

3.2 QoS等级详解:消息能送到吗?

MQTT定义了三个服务质量等级。说白了,就是决定消息“到底能不能送到,送到几次”。

QoS等级 含义 可靠性 性能开销
0 至多一次(At most once) 最低,可能丢消息 最低
1 至少一次(At least once) 中等,保证送达,但可能重复 中等
2 恰好一次(Exactly once) 最高,保证送达且不重复 最高

QoS 0: 发出去就不管了。就像你往河里扔块石头,扔完就走,不管它沉没沉。适合那些丢了也无所谓的场景,比如环境温度,丢一两个数据点不影响大局。

QoS 1: 保证消息至少到达一次。Broker收到后会回复一个确认包(PUBACK)。如果发布者没收到确认,就会重发。这会导致订阅者可能收到重复消息。我建议,如果你的应用能处理重复数据(比如用时间戳去重),QoS 1是性价比最高的选择。

QoS 2: 最严格,也最慢。它通过两次确认(PUBREC、PUBREL、PUBCOMP)来确保消息既不丢失也不重复。说实话,我在实际项目中很少用QoS 2。为什么?因为性能开销太大了。只有在控制指令这种“发错一次就完蛋”的场景下,我才会考虑它。比如,给机械臂发“急停”指令,必须用QoS 2。

避坑指南: 我曾经在一个项目中,把所有数据都设成了QoS 2。结果Broker CPU直接飙到100%,消息堆积如山。后来改成QoS 1,一切正常。记住:不要滥用QoS 2,它不是你想象中“更安全”的万能药。

3.3 主题(Topic)与通配符:消息的“门牌号”

主题,就是消息的地址。它是个字符串,用“/”分层。比如:

factory/line1/robot/arm/temperature
factory/line1/robot/arm/status
factory/line2/robot/arm/temperature

这种分层结构,让消息管理变得非常清晰。你可以把不同车间、不同产线、不同设备的数据,都组织到一棵“主题树”里。

但问题来了:如果我想订阅“所有机器人的温度”,难道要一个一个写主题吗?不用。MQTT提供了两个通配符:

  • 单层通配符(+):匹配一层。比如订阅 factory/+/robot/arm/temperature,就能匹配到line1和line2的温度。
  • 多层通配符(#):匹配剩余所有层。比如订阅 factory/#,就能收到factory下所有主题的消息。

我个人习惯,在调试阶段用 # 来抓取所有数据,非常方便。但生产环境,千万别这么干!为什么?因为订阅 # 会收到Broker上所有的消息,流量巨大,客户端根本扛不住。

重要提醒: 通配符只能用在订阅端,不能用在发布端。发布消息时,必须指定一个具体的、不含通配符的主题。

3.4 保留消息与遗嘱消息:Broker的“记忆”与“遗言”

这两个特性,是MQTT在工业场景中非常好用的“杀手锏”。

保留消息(Retained Message):

想象一下,你新装了一个温度传感器,它每隔10秒发一次数据。但你的监控系统是后来才启动的。它一启动,能立刻拿到当前温度吗?

如果没有保留消息,它必须等10秒,等传感器下一次发布。有了保留消息,传感器可以在发布时设置 retain=true。Broker会记住这条消息。当新的订阅者上线时,Broker会立刻把这条“保留消息”推送给它。

说白了,保留消息就是Broker的“记忆”。它让新订阅者能立即获取到设备的“最新状态”,而不是傻等。我在做设备状态监控时,每个设备都会发布一条保留消息,内容就是它的当前状态(运行/停止/故障)。这样,任何客户端一上线,就能立刻看到所有设备的实时状态。

遗嘱消息(Will Message):

这个特性,我称之为“最后的遗言”。

设备在连接Broker时,可以设置一个遗嘱消息。如果设备非正常断开(比如掉电、断网),Broker会替它发布这条遗嘱消息。

举个例子:你有一个PLC,它正常运行时,每隔5秒发布一次心跳。同时,它在连接时设置了遗嘱消息:topic: factory/line1/plc/status, payload: offline。如果PLC突然掉线,Broker检测到连接断开,就会立刻发布这条遗嘱消息。你的监控系统订阅了这个主题,就能立刻知道“PLC离线了”,从而触发报警。

我的经验: 遗嘱消息的QoS等级,我建议至少设为1。为什么?因为如果遗嘱消息丢了,你就永远不知道设备离线了。另外,遗嘱消息的topic最好和正常数据分开,比如用 /status/will 后缀,方便订阅者区分。

嗯,到这里,MQTT的基础就回顾完了。这些概念,在后面的OPC UA与MQTT融合通信中,会反复用到。尤其是主题设计和QoS选择,直接决定了你整个系统的稳定性和实时性。别急,后面我们一步步实战。