第8篇_PLC侧MQTTBroker现场排障_连不上订阅失败发布延迟Retain收不到该怎么查
Broker 写出来以后,真正考验它的不是“演示能不能跑”。
真正考验是现场出了问题时:
你能不能在 5 分钟内判断问题在哪一层。
先给结论:
PLC Broker 排障不要先猜网络,也不要只看客户端日志。
正确方式是按层看:监听层、接入层、CONNECT 解析、订阅表、路由、发送队列、Retain 表、QoS 事务。
一、排障总图

这张图的核心是:
不要一上来就改代码。
先定位层级。
二、连不上怎么查
连不上先看这些变量:
| 变量 | 正常期望 | 异常含义 |
|---|---|---|
xRunning |
TRUE |
Broker 未进入运行态 |
hListenHandle |
非 0 | TCP 监听未建立 |
xTcpServerError |
FALSE |
监听层错误 |
xTcpAcceptActive |
连接瞬间可能 TRUE | 有客户端尝试接入 |
uiAcceptFreeSlot |
非 0 | 有空闲槽位 |
uiActiveSlotCount |
随连接数变化 | 当前活跃客户端数 |
aSnapshots[x].xUsed |
连接后保持 TRUE | 槽位是否保住 |
如果这些值在连接过程中不断闪:
xTcpAcceptActive 闪
uiAcceptFreeSlot 闪
uiActiveSlotCount 闪
优先看槽位释放前快照:
| 字段 | 判断 |
|---|---|
udiLastBytesRead = 0 |
可能首包还没到就释放 |
udiLastBytesRead > 0 |
已读到 MQTT 报文 |
xLastConnectParsed = FALSE |
CONNECT 解析失败 |
eLastParseError |
解析失败原因 |
byLastConnectLevel |
协议级别读取结果 |
如果要在用户程序里做一个最小诊断观察,建议至少把 Broker 实例和快照暴露出来:
// 示例:在线监控时优先观察这些输出,而不是只盯客户端日志。
xBrokerRunning := fbBroker.xRunning;
xBrokerError := fbBroker.xError;
eBrokerError := fbBroker.eLastError;
uiActiveSlotCount := fbBroker.uiActiveSlotCount;
uiAcceptFreeSlot := fbBroker.uiAcceptFreeSlot;
stSlot1Snapshot := fbBroker.aSnapshots[1];
三、CONNECT 失败怎么查
CONNECT 失败最有效的判断表:
| 现象 | 判断 |
|---|---|
udiLastBytesRead = 0 |
TCP 接入有了,但 MQTT 首包未到 |
sLastProtocolName = MQTT 且 level 4 |
MQTT 3.1.1 |
sLastProtocolName = MQTT 且 level 5 |
MQTT 5.0 |
sLastProtocolName = MQIsdp 且 level 3 |
MQTT 3.1 老协议 |
byLastConnectLevel = 100 |
协议级别偏移错误,读到字符 d |
| MQTT 5.0 连接后断开 | 看 CONNACK 是否返回零属性长度 |
经验结论:
TCP 已读到数据,就不要继续纠结“网线通不通”。
这时问题已经进入 MQTT 报文层。
四、订阅失败怎么查
订阅失败优先看:
| 变量 / 报文 | 作用 |
|---|---|
| SUBACK 返回码 | 客户端订阅是否被 Broker 接受 |
uiSubItemCount |
多 Topic 是否全部解析 |
| Topic Filter | 是否合法 |
| ACL 规则 | 是否被权限拒绝 |
| 订阅表 | 是否写入对应槽位 |
快速判断表:
| 现象 | 可能原因 |
|---|---|
| 客户端直接显示订阅失败 | SUBACK 返回 0x80 |
| 单 Topic 成功,多 Topic 丢项 | 解析循环不完整 |
device/#/status 失败 |
# 位置非法 |
device/a+ 失败 |
+ 未独占层级 |
| 订阅成功但收不到 | 路由匹配或订阅表问题 |
五、发布收不到怎么查
发布成功但订阅端收不到,一般分三层:
排查表:
| 层级 | 看什么 |
|---|---|
| PUBLISH 解析 | Topic Name、Payload 长度、QoS |
| Router | F_MqttTopicMatch、订阅表 |
| 投递队列 | uiDeliveryQueueCount、队列满计数 |
| TCP 写出 | uiLastTxFrameCount、uiLastTxBytes |
| QoS ACK | TxInflight 状态 |
如果同一主题两个客户端互发,最好先用 QoS0 测通,再测 QoS1 / QoS2。
六、发布延迟怎么查
延迟问题不要靠感觉。
看这些字段:
| 字段 | 判断 |
|---|---|
uiDeliveryQueueCount 长期大于 0 |
发送出口跟不上 |
uiProtocolQueueCount 长期大于 0 |
协议响应被拖慢 |
uiLastTxFrameCount 长期为 1 |
批量写出没生效 |
uiLastTxFrameCount 常见 1~2 |
小消息批量程度有限,但可能够用 |
uiMaxDeliveryQueueCountSeen 很高 |
曾出现瞬时堆积 |
当前推荐默认:
cnMaxFramesPerConnectionScan = 8
cnMaxTxFramesPerWrite = 8
cnConnectFirstReadDelayMs = 20
cnConnectionInactiveGraceMs = 3000
通信猫高频崩溃但 MQTTBox 正常时,不要盲目把 Broker 参数继续拉大。
这更像客户端工具承压。
七、Retain 收不到怎么查
Retain 验收必须用“新订阅”测。
| 步骤 | 期望 |
|---|---|
A 发布 CodeSys,Retain=1 |
Broker Retain 表数量增加 |
B 重新订阅 CodeSys |
B 立即收到保留消息 |
| A 发布空 Payload,Retain=1 | Broker 清除该 Topic Retain |
| B 再重新订阅 | 不应再收到旧 Retain |
排查变量:
| 变量 | 作用 |
|---|---|
uiRetainCount |
当前 Retain 数量 |
sLastRetainTopic |
最近 Retain 命中主题 |
uiLastRetainPayloadLen |
最近 Retain Payload 长度 |
| Retain 补发队列 | 新订阅是否触发补发 |
八、最常见的 8 个坑
| 坑 | 正确处理 |
|---|---|
| 以为多个客户端连 1883 是端口冲突 | 这是 Broker 正常模型 |
| 槽位一闪就释放就怀疑网络 | 先看首包等待和 Active 容忍 |
只支持 MQTT 协议名 |
还要兼容 MQIsdp |
| MQTT 5.0 CONNACK 少一个零属性长度 | 客户端可能直接断 |
| 订阅表只存字符串 | 必须绑定槽位和 QoS |
| PacketId 直接沿用发布者 | 转发给订阅者要重新分配 |
| Retain 只看发布成功 | 新订阅补发才是真验收 |
| 性能慢就盲目加队列 | 先看批量写帧数和写事务 |
排障结论分级
现场排障最忌讳一句话定罪。Broker 侧至少要把结论分成三类。
| 结论类型 | 可以怎么说 | 需要什么证据 |
|---|---|---|
| high | TCP 已读到 CONNECT,问题进入 MQTT 解析层 | udiLastBytesRead > 0,且有解析错误 |
| medium | 延迟大概率在发送出口 | 队列水位、uiLastTxFrameCount、客户端时间戳能对上 |
| low | 可能是某个客户端工具承压 | 只有客户端崩溃现象,没有 Broker 错误和抓包 |
Ben 式排障不是把话说满,而是把证据对象钉住。
如果只有客户端日志,没有 PLC 快照和抓包,那最多只能列第一怀疑组;如果 PLC 快照、Broker 诊断和客户端日志三边能对上,结论才可以往 high 提。
九、这一篇你最该记住的 6 句话
- Broker 排障要按层,不要先猜。
- 连不上先看监听、接入、槽位和 CONNECT。
- 订阅失败先看 SUBACK、Topic Filter 和订阅表。
- 发布收不到先看路由匹配和目标投递队列。
- 发布延迟先看
uiLastTxFrameCount和队列水位。 - Retain 是否实现,要用新订阅补发来验证。
下篇预告
主线 8 篇到这里结束。
下一篇是加更:
PLC Broker 要不要完整支持 MQTT 5.0?工业现场别被“新版本”带偏。
我会讲为什么当前轻量 Broker 选择 MQTT 5.0 基础兼容,而不是一上来做完整属性系统。
完整 ST 代码
本篇涉及的完整代码入口:
MqttBroker/Device/Application/DUTs/ST_MqttBrokerConnectionSnapshot.stMqttBroker/Device/Application/DUTs/ST_MqttBrokerDiagItem.stMqttBroker/Device/Application/DUTs/ST_MqttBrokerMetrics.stMqttBroker/Device/Application/POUs/FBs/FB_MqttBroker.M_LogDiag.stMqttBroker/Device/Application/POUs/FBs/FB_MqttBroker.M_ClearDiag.stMqttBroker/Device/Application/POUs/FBs/FB_MqttBroker.M_KickClient.st
系列导航
- 系列定位:第 8 篇
- 上一篇:为什么 PLC Broker 会有延迟?从 TCP_Write 一帧一写到批量粘包写出
- 下一篇:加更 1:PLC Broker 要不要完整支持 MQTT 5.0?
项目与资料
- 开源项目名称:
MqttBroker - 前置系列:
MqttClient_V2_0 - 核心关键词:现场排障、诊断快照、Retain、连接闪烁、发布延迟
适合谁收藏
- 已经把 Broker 跑起来,但现场问题不断的人
- 需要给同事做 MQTT Broker 排障培训的人
- 想把 PLC 在线变量变成诊断体系的人
- 正在整理产品手册和技术支持文档的人
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)