MQTT 协议基础:发布/订阅模型、主题与通配符、QoS 等级、保留消息与遗嘱消息
聊 MQTT,咱们得先搞清楚它到底是个什么路子。说白了,它不是那种「你问我答」的传统通信协议,而是一种发布/订阅模式。我刚开始接触工业物联网那会儿,总觉得这玩意儿跟 HTTP 差不多,后来在产线上踩了坑才明白——完全两码事。
发布/订阅模型:解耦才是王道
传统客户端-服务器模型里,客户端直接跟服务器对话。但 MQTT 不一样,它中间夹了一个Broker(消息代理)。所有设备都不直接通信,而是通过 Broker 中转。
核心角色就三个:
- Publisher(发布者):只管发消息,不管谁收
- Subscriber(订阅者):只管收消息,不管谁发
- Broker(代理):负责消息路由和分发
我在一个智慧工厂项目里遇到过这种情况:现场有 200 多个传感器,每个都要跟中央系统通信。如果用 HTTP,每个传感器都得维护一个长连接,服务器压力巨大。换成 MQTT 后,传感器只管往 Broker 丢数据,中央系统订阅自己关心的主题就行。服务器负载直接降了 60%。
这种模型的好处很明显——发布者和订阅者完全解耦。它们不需要知道对方的存在,不需要同时在线,甚至不需要在同一网段。你想想看,这对工业现场有多重要?设备可能分布在不同的车间、不同的楼层,网络环境千差万别,解耦之后,整个系统的弹性就上来了。
主题(Topic)与通配符:消息的路由规则
主题是 MQTT 消息的路由标签。它不像 IP 地址那样是数字,而是层级结构的字符串,用斜杠 / 分隔。
举个例子:
factory/workshop1/temperature
factory/workshop1/humidity
factory/workshop2/temperature
这种结构的好处是——你可以按车间、按设备类型、按数据维度来组织消息。我习惯把主题设计成 站点/区域/设备类型/数据点 这种格式,这样后期扩展起来特别方便。
通配符:订阅的灵活利器
MQTT 提供了两个通配符,让你可以一次订阅多个主题:
| 通配符 | 含义 | 示例 | 匹配结果 |
|---|---|---|---|
+ |
匹配单层 | factory/+/temperature |
匹配所有车间的温度数据 |
# |
匹配多层 | factory/# |
匹配 factory 下所有数据 |
注意:# 通配符只能放在主题末尾,不能出现在中间。比如 factory/#/temperature 是无效的。我曾经有个同事这么写过,结果 Broker 直接报错,排查了半天才发现是通配符位置不对。
通配符用好了,能大幅减少订阅数量。比如你要监控整个工厂的所有温度数据,只需要订阅 factory/+/temperature 这一个主题就行,不用每个车间都订阅一次。
QoS 等级详解:消息可靠性的三个档次
QoS(Quality of Service)是 MQTT 保证消息可靠性的机制。它分三个等级,每个等级对应不同的开销和可靠性。
| QoS 等级 | 名称 | 发送次数 | 确认机制 | 适用场景 |
|---|---|---|---|---|
| 0 | 至多一次 | 1 次 | 无确认 | 环境温度、湿度等非关键数据 |
| 1 | 至少一次 | 至少 1 次 | PUBACK 确认 | 设备状态、报警信息 |
| 2 | 恰好一次 | 2 次握手 | PUBREC/PUBREL/PUBCOMP | 控制指令、关键参数写入 |
QoS 0: 发出去就不管了,不确认、不重发。性能最好,但可能丢消息。适合那些丢了也无所谓的场景,比如温度采集,每秒都在更新,丢一两个没关系。
QoS 1: 保证消息至少到达一次,但可能重复。Broker 收到消息后会回复 PUBACK,如果发布者没收到确认,就会重发。我在一个设备状态监控项目里用的就是 QoS 1,因为设备状态变化不频繁,但丢了就麻烦了。
QoS 2: 最可靠,但开销最大。它通过四次握手保证消息不丢不重。适合控制指令,比如「关闭阀门」「启动电机」。我曾经在一条自动化产线上用过 QoS 2 下发启动指令,虽然延迟比 QoS 1 高了 30 毫秒,但保证了指令不会重复执行——重复启动电机可是会烧设备的。
我的建议:不要所有消息都用 QoS 2。工业现场消息量大的时候,QoS 2 的握手开销会拖垮 Broker。我一般遵循「非关键用 QoS 0,状态用 QoS 1,控制用 QoS 2」的原则。
保留消息与遗嘱消息:两个容易被忽略的利器
这两个功能在工业场景里特别实用,但很多人容易忽略。我刚开始用 MQTT 的时候也完全没在意,直到有一次设备掉线后系统完全不知道发生了什么,才意识到它们的重要性。
保留消息(Retained Message)
保留消息是 Broker 上保存的最后一条消息。新订阅者上线时,Broker 会立即把保留消息推送给它。
有什么用?举个例子:
你有一个温度传感器,它每隔 5 秒发布一次温度数据。新上线的监控系统如果等 5 秒才能看到第一个数据,那这 5 秒就是盲区。但如果传感器发布消息时设置了 retain=true,Broker 就会保存最后一条温度数据。新系统一订阅,立刻就能拿到当前温度。
// 发布保留消息示例(伪代码)
client.publish("factory/workshop1/temperature", "25.3", {
qos: 1,
retain: true
});
注意:保留消息只保存每个主题的最后一条。如果某个主题不再更新,Broker 会一直保留旧数据。我建议定期清理不需要的保留消息,或者用空消息覆盖掉。
遗嘱消息(Will Message)
遗嘱消息是设备异常断开时,由 Broker 代发的最后一条消息。设备在连接时就要设置好遗嘱主题和内容。
场景:你有一台 PLC,它正常运行时每隔 10 秒发布一次心跳。如果 PLC 突然断电或断网,Broker 检测到连接断开后,就会自动发布遗嘱消息,比如 factory/plc1/status = "offline"。
// 设置遗嘱消息示例(伪代码)
client.connect({
will: {
topic: "factory/plc1/status",
payload: "offline",
qos: 1,
retain: true
}
});
我在一个污水处理厂项目里用过遗嘱消息。现场有 30 多台 PLC,每台都设置了遗嘱。有一次一台 PLC 的网线被老鼠咬断了,中央监控系统立刻收到了离线通知,运维人员 10 分钟就赶到了现场。如果没有遗嘱消息,可能要等到下一次轮询才能发现故障——那会儿污水可能已经溢出来了。
避坑指南:遗嘱消息的 QoS 等级要跟实际场景匹配。如果遗嘱消息丢了,你就永远不知道设备离线了。我一般把遗嘱消息设成 QoS 1 或 QoS 2,确保它一定能到达。
本章知识体系
下面这张图把 MQTT 协议基础的核心逻辑串起来了。你可以看到发布/订阅模型如何运作,主题和通配符怎么路由消息,QoS 等级怎么保证可靠性,以及保留消息和遗嘱消息在什么时机发挥作用。
嗯,这一章的内容就这些。MQTT 的基础概念其实不复杂,但每个细节在工业场景里都有它的用武之地。主题设计得好,后期维护就省心;QoS 选得对,系统可靠性就有保障;保留消息和遗嘱消息用好了,能避免很多「设备掉线了都不知道」的尴尬局面。