读写器资产与 ERP 之间的典型第一版集成是 HTTP:网关把每批读取 POST 到一个端点,Odoo 收下,大家下班。三个月后,这个端点在峰值下开始超时,网关对着墙不断重试,而丢掉的那些事件恰好就是能解释库存差异的那批。
MQTT 是常见的解法,而且是个好解法——但前提是把它理解为「带有特定保证的传输层」,而不是一个能魔法般让问题消失的队列。
为什么 HTTP 轮询在 RFID 事件率下会失败
这不是调参问题,而是结构问题。
- 轮询意味着客户端去问;每小时一万枚标签时,「问」这个动作本身就成了负载。
- ERP 响应一慢就阻塞网关,于是读写器要么在内存里缓冲,要么在边缘把事件丢掉。
- 网络抖动把一次同步调用变成超时,把超时变成一条没有被记录下来的读取。
- 没有天然的反向通道:Odoo 无法告诉网关放慢、换模式,或者重读某个区域。
- 重试风暴会放大原问题,因为每个失败请求都会被重复,而新事件还在源源不断到来。
发布订阅改变了什么
消息代理在两侧之间插入了一个持久、可寻址的缓冲,而这改变了故障模式。
- 读写器只管发布然后忘掉;投递从读写器的问题变成了代理的问题。
- 业务侧按自己的节奏订阅,所以变慢的是桥接层,不是无线电。
- 主题提供了路由词汇:站点、区域、读写器与事件类型都可以被单独寻址。
- 消费端重启期间代理可以缓冲,于是一次停机变成了一次延迟。
- 命令主题让 Odoo 或操作员能把配置推回读写器。
主题树就是契约
大多数 MQTT 集成后期难维护,都是因为主题结构是即兴发挥的,而现在每个消费方都在解析字符串。
- 层次只设计一次:站点、区域、读写器、事件类型,顺序永远固定。
- 原始读取发在一支,解析后的业务事件发在另一支;它们面向不同的消费方,保留策略也不同。
- 状态与心跳单独一支,这样一台死掉的读写器不需要翻事件流就能看见。
- 通配符对工具很方便,对生产消费方很危险,因为一个订阅可能悄悄变宽。
- 给主题树做版本,而不只给载荷做版本;改一级名字比改一个字段破坏性更大。
载荷设计:小、有版本、自描述
载荷也是契约,设计错了,代价会晚到。
- 每条事件都带上要点:读写器事件时间、读写器标识、天线、EPC、信号强度与单调序号。
- 优先用设备发出的毫秒时间戳,网关接收时间放在另一个字段里。
- 能扁平就扁平;嵌套结构更难校验,也更难建索引。
- 显式携带模式版本与固件版本,因为字段行为随固件变化的频率高于随模式变化。
- 只在带宽真的紧张时才压缩;一个塞满二进制块的代理,是没人能调试的代理。
QoS、保留消息,以及它们真正保证了什么
三个 QoS 等级被广泛描述,也被广泛误解。
- QoS 0 是发完就忘:适合高频原始读取,因为一秒后的下一次读取就会替代它。
- QoS 1 保证至少送达一次,也就是会有重复,而重复意味着桥接层必须幂等。
- QoS 2 在协议层保证恰好一次,代价是每条消息一次四步握手。
- 保留消息是给状态的,不是给事件的:最后一台读写器的已知状态属于那里,一次标签读取不属于。
- 遗嘱消息是让死掉的读写器在几秒内可见、而不是等到下次盘点才被发现的关键。
桥接层:协议变成业务事件的地方
桥接层是一个有状态的真实应用,价值正是在这里被创造或毁掉。
- 订阅原始读取,按 EPC 在时间窗内去重,再聚合成带符号的增量。
- 用缓存映射把 EPC 解析成产品与批次,未知标签路由到隔离主题。
- 通过单一写入进程、带幂等键写入 Odoo,绝不让多个桥接实例同时写。
- 只在业务写入提交之后才 ACK 那条 MQTT 消息,否则你会在最糟的时刻丢事件。
- 把已解析事件回发到业务分支,这样其他消费方不必重复这项工作。
背压、重放与毒消息
每条事件管道最终都会遇到一条处理不了的消息,设计问题是那时会发生什么。
- 给在途消息设上限;无上限的消费者只是换一种方式把内存耗尽。
- 队列深度超过上限时,带计数器地丢弃而不是阻塞读写器,并大声告警。
- 把无法处理的消息送到死信主题并附上原因,绝不让一条消息卡住整个队列。
- 保存单调序号,让重放可以从一个已知点开始,而不是靠猜。
- 主动测试重放路径;没测过的重放是信念,不是能力。
安全:TLS、凭证与主题 ACL
一个没有访问控制的仓库 MQTT 代理,就是一个可以篡改库存的接口。
- 在标准安全端口上启用 TLS,并彻底关闭明文监听。
- 给每台读写器独立的凭证或客户端证书,这样一台设备被攻破可以单独吊销。
- 按主题分支限制发布与订阅权限,读写器不能发布到别的站点分支。
- 关闭匿名访问和默认管理员账号;这两项至今仍是审计中最常见的发现。
- 记录连接与授权失败,因为它们是设备配置错误或敌意行为最早的信号。
运维:你现在拥有了一台代理
引入代理就意味着引入一个必须像其他系统一样被监控的系统。
- 跟踪在线客户端数、消息速率、丢弃消息数与持久会话深度。
- 对桥接滞后、最旧未处理消息的年龄、死信增长告警。
- 按峰值小时做容量规划,而不是按日均,并在忙碌班次中测试一次代理重启。
- 备份保留状态与桥接映射表;它们是配置,不是缓存。
- 把主题树与载荷模式写进代码仓库,因为下一次集成会由别人来写。






