2. 工业MQTT基础

在Sparkplug B数据建模之前,必须先理解它所依赖的传输底座——MQTT。MQTT是一种轻量级的发布/订阅消息协议,专为低带宽、不稳定网络和资源受限设备设计,这恰好与工业现场大量PLC、传感器、网关的运行环境高度吻合。本节围绕四个核心机制展开:发布订阅模式、QoS等级、保留消息与遗嘱消息,并结合工业场景说明它们各自解决什么问题。

一、核心原理:发布订阅与Broker解耦

MQTT采用发布/订阅模式,而不是传统的请求/响应模式。系统中存在三类角色:发布者(Publisher)、订阅者(Subscriber)和消息代理(Broker)。发布者不直接把消息发给某个设备,而是把消息发布到某个主题(Topic);订阅者通过订阅主题表达式来接收消息;Broker负责主题匹配与消息转发。这种解耦带来三个工业价值:设备之间不需要知道彼此地址、新增订阅者不影响发布者、网络中断时可通过会话机制缓冲。

主题是分层字符串,用斜杠分隔,例如 factory/line1/plc01/temperature。订阅时支持通配符:+ 匹配单层,# 匹配多层。工业中常用 factory/line1/# 订阅整条产线数据。需要特别注意:主题区分大小写,且以 $ 开头的主题(如 $SYS/)是Broker系统主题,业务订阅不应与之冲突。

MQTT 发布/订阅模式与工业角色映射 MQTT Broker 主题匹配 / 转发 会话 / 保留 / 遗嘱 PLC / 传感器 发布者 Publisher 边缘网关 发布者 Publisher SCADA 采集端 发布者 Publisher 云平台 / 数据库 订阅者 Subscriber HMI 监控画面 订阅者 Subscriber MES / 分析服务 订阅者 Subscriber factory/line1/plc01/temp factory/line1/gw01/status factory/line1/# 订阅 factory/# 订阅 factory/line1/+ 订阅 factory/line1/plc01/#

二、QoS等级:可靠性与开销的权衡

MQTT定义了三个服务质量等级,决定消息投递的保证程度。工业场景中不能一律使用最高等级,需要按数据重要性分级配置。

QoS 投递语义 交互次数 工业适用场景
QoS 0 最多一次,可能丢失 1 次(PUBLISH) 高频温度/振动采样,丢一帧不影响趋势判断
QoS 1 至少一次,可能重复 2 次(PUBLISH + PUBACK) 设备状态、报警触发,允许重复但不可丢失
QoS 2 恰好一次,不丢不重 4 次(PUBLISH + PUBREC + PUBREL + PUBCOMP) 计量结算、配方下发、关键控制指令

需要强调的是,QoS是发布端与Broker之间、Broker与订阅端之间分别协商的,最终生效等级取两者较小值。例如发布用QoS 2、订阅用QoS 1,实际投递为QoS 1。工业调试中常见“明明设了QoS 2却仍重复”的问题,往往就是订阅端等级不匹配。

三、保留消息与遗嘱消息:状态可见性与故障感知

保留消息(Retained Message):发布时设置 retain 标志,Broker会为该主题保存最后一条消息。新订阅者一旦订阅该主题,立即收到这条保留消息,无需等待下一次发布。工业价值在于:HMI或云平台刚上线时,能立刻看到设备当前状态,而不是空白等待。注意保留消息只保留最后一条,且发布空载荷可清除保留。

遗嘱消息(Will Message):客户端连接时预先向Broker注册一条遗嘱。当客户端异常断开(网络中断、设备掉电、心跳超时)时,Broker自动代其发布遗嘱消息。工业价值在于:网关或PLC离线时,监控端能立即收到“设备离线”通知,而不是靠轮询超时判断。

# 遗嘱消息注册示例(伪代码)
CONNECT clientId="gw-line1-01"
  willTopic   = "factory/line1/gw01/status"
  willPayload = "OFFLINE"
  willQos     = 1
  willRetain  = true
  keepAlive   = 30

# 正常上线后主动发布在线状态
PUBLISH topic="factory/line1/gw01/status"
        payload="ONLINE"
        qos=1
        retain=true
将遗嘱消息与保留消息配合使用效果最佳:遗嘱设置 retain=true,则设备离线后,任何新订阅者都会立即看到“OFFLINE”保留状态,实现状态自描述。

四、工业场景案例:一条产线的数据链路

假设某汽车焊装线,PLC01采集焊枪温度,网关GW01汇聚数据,云平台做趋势分析,HMI显示实时状态。配置如下:

  • PLC01 发布 factory/line1/plc01/temperature,QoS 0,每秒1次,不保留——高频数据无需保留。
  • GW01 发布 factory/line1/gw01/status,QoS 1,retain=true,并注册遗嘱 payload="OFFLINE"——状态必须可见。
  • 云平台订阅 factory/line1/#,QoS 1——接收全部产线数据。
  • HMI 订阅 factory/line1/+/status,QoS 1——只关心各设备在线状态。

当GW01网络中断,Broker在keepAlive超时后发布遗嘱“OFFLINE”,HMI立即变红告警;云平台因订阅了 # 也同步收到。恢复后GW01重新发布“ONLINE”保留消息,新上线的HMI无需等待即可看到绿色状态。

五、常见误区与复盘

误区一:所有主题都设 retain=true。高频温度数据若保留,Broker会持续保存最后一条,新订阅者收到的是过期值,可能误判。保留应只用于状态类、配置类主题。

误区二:QoS 2 一定最好。QoS 2 四次握手带来延迟和带宽开销,高频数据用QoS 2会拖垮Broker。应按数据重要性分级。

误区三:遗嘱消息等于断线检测。遗嘱依赖keepAlive超时,默认可能长达1.5倍keepAlive。工业场景应把keepAlive设为10~30秒,并配合应用层心跳。

误区四:主题设计随意。主题一旦被大量订阅者依赖,后期重构成本极高。建议在项目初期就按“厂区/产线/设备/测点”四层规范命名,并预留Sparkplug B的命名空间。

掌握以上四个机制后,就能理解Sparkplug B为何要在MQTT之上再定义一套主题命名、载荷编码和状态管理规范——它正是为了解决原生MQTT在工业场景中主题混乱、数据格式不统一、状态语义缺失的问题。下一层建模将建立在这些基础机制之上。