MQTT 主题树不只是命名规则。它最终会成为路由 API、授权边界、可观测维度,以及设备固件与后端服务之间长期存在的契约。
薄弱的主题结构在 Demo 中似乎没有问题,因为所有客户端都订阅 #。当租户、站点、设备类型和团队不断增长时,它会迅速变得昂贵。
先制定 MQTT 主题命名规范
一套有效的 MQTT 主题命名规范应便于判断:
- 谁拥有这条消息?
- 它属于哪个租户、站点或环境?
- 哪个资产或设备产生了它?
- 它是遥测、状态、事件还是指令?
- 哪些消费者有权读取它?
一种可行结构是:
{environment}/{tenant}/{site}/{deviceType}/{deviceId}/{channel}
例如:
prod/acme/shanghai/pump/pump-042/telemetry
prod/acme/shanghai/pump/pump-042/state
prod/acme/shanghai/pump/pump-042/command
不存在适合所有系统的固定顺序。应让最常用的订阅过滤器和授权规则足够窄,并且容易理解。
在固件发布前,应统一应用规范并评审具体示例:
| 较弱的主题 | 更好的主题 | 改进原因 |
|---|---|---|
sensor1/temp | prod/acme/shanghai/sensor/device-042/telemetry | 增加稳定的所有权、环境和设备上下文 |
factory/# | prod/acme/shanghai/+/+/telemetry | 把订阅收窄到一个站点和通道 |
device-042/temperature/22.4 | prod/acme/shanghai/sensor/device-042/telemetry | 把变化数据留在载荷中 |
alice-phone/status | prod/acme/mobile/client-7f3a/state | 移除个人信息并使用稳定标识符 |
使用稳定身份
主题层级应使用稳定的机器标识符。“锅炉房水泵”这类显示名称可能修改、包含空格或需要翻译,应放在设备元数据或载荷中。
不要用网络地址作为设备身份。IP、蜂窝标识或网关路由都可能在设备生命周期内发生变化。
分离消息方向与含义
把遥测和指令混在一个没有区分的主题下,会让权限很难审查。
更清晰的模式是分离通道:
.../{deviceId}/telemetry
.../{deviceId}/state
.../{deviceId}/event
.../{deviceId}/command
.../{deviceId}/command-result
现场设备可以发布遥测、状态、事件和指令结果,但只订阅自己的指令主题。后端服务拥有更宽的读取权限,以及谨慎控制的指令写入权限。
把通配符视为权限
+ 和 # 很强大,因为一条订阅可以代表整组设备:
prod/acme/shanghai/pump/+/telemetry
同样的能力也可能跨越所有权边界:
prod/#
只有确实需要的可信服务才应拥有宽泛的多层订阅。现场设备几乎不应获得超出自身身份范围的通配符权限。
策略测试必须覆盖拒绝场景:
- 设备 A 能否冒充设备 B 发布?
- 传感器能否向指令主题发布?
- 一个租户能否订阅另一个租户?
- 通配符能否逃逸出预期前缀?
不要把载荷结构塞进主题
主题负责路由,不应编码每个字段。避免:
device-042/temperature/22.4/celsius/battery/91
应使用稳定主题和结构化载荷:
prod/acme/shanghai/sensor/device-042/telemetry
{
"schemaVersion": 2,
"temperature": 22.4,
"temperatureUnit": "C",
"batteryPercent": 91,
"observedAt": "2026-07-27T11:04:00Z"
}
这样载荷演进时,授权规则仍能保持稳定。
有计划地版本化破坏性变更
不要习惯性给所有主题加 v1。许多载荷调整具备向后兼容性,可以通过载荷中的 Schema 版本处理。
只有路由或权限含义改变时,才需要对主题版本化:
prod/acme/v2/shanghai/pump/pump-042/event
迁移阶段可以让发布者同时发送两个版本,消费者独立迁移。应记录旧版本下线日期,并监控旧分支仍存在的订阅。
明确保留状态与指令约定
每个通道都应记录:
- 是否允许保留消息;
- 使用 QoS 0 还是 1;
- 最大载荷大小;
- 是否必须设置过期时间;
- 是否必须包含操作 ID;
- 是否会产生结果或确认;
- 是否包含个人或受监管数据。
指令通常必须包含过期时间和幂等信息。设备离线数日后重连时,不应仅因为旧指令仍在队列就执行过期操作。
评审清单
冻结主题契约前:
- 写出五个最常见的发布与订阅示例。
- 分别写出一台设备、一个网关和一个后端服务的权限。
- 添加拒绝场景测试。
- 检查是否有层级暴露秘密或个人信息。
- 确认设备替换或站点迁移后标识符仍稳定。
- 明确载荷 Schema 的责任方与兼容策略。
- 为每个通道定义 Retain、QoS、过期和队列规则。
- 记录破坏性变更如何上线和下线。
RunMQTT 使用可复用策略模板表达发布与订阅过滤器,让评审过的契约可以分配给同类设备。完整的身份与授权模型请阅读 MQTT 安全指南。
要继续完善 QoS、重试、队列和可观测性约定,请使用 MQTT 最佳实践清单。
