MQTT 是一种轻量级发布订阅协议,客户端通过 Broker 交换消息。它的报文开销很小,但更重要的优势来自架构:发布者不需要知道有哪些消费者,订阅者也不需要知道事件来自哪一台设备。
这种解耦使 MQTT 非常适合传感器遥测、设备状态、远程指令、边缘网关、移动客户端,以及经常处于不稳定网络中的服务。
本文不罗列报文名称,而是围绕真实系统中会影响可靠性与安全性的关键决策展开。
MQTT 协议是什么?
MQTT 是一种应用层消息协议,通过 Broker 把发布者的消息路由给订阅者。客户端建立长连接后向层级主题发布载荷,并通过主题过滤器订阅消息,不需要依赖对方的地址或在线状态。这种解耦让设备和服务集成保持简单,同时由 Broker 集中处理认证、授权、投递状态与可观测性。
MQTT 系统的四个核心概念
一个 MQTT 系统通常包含四部分:
- Broker:接收连接、验证客户端、检查主题权限并路由消息。
- 客户端:任何连接到 Broker 的设备或进程,可以发布、订阅,也可以同时完成两者。
- 主题:类似
factory/site-a/line-2/motor-7/temperature的层级地址。 - 消息:载荷加上 QoS、保留标志、过期时间和 MQTT 5 属性等投递设置。
客户端不会把 MQTT 消息直接发给另一台客户端。Broker 始终是消息路由与访问控制的边界。
建立连接时发生了什么
客户端首先与 Broker 建立网络连接。生产环境通常使用基于 TLS 的 MQTT,常见端口是 8883。浏览器不能直接打开任意 TCP Socket,因此 Web 客户端通常通过安全 WebSocket 承载 MQTT。
端口号只是起点,真正需要确定的是传输方式和安全策略:
| 端口 | 常见传输方式 | 适用场景 |
|---|---|---|
| 1883 | 不带 TLS 的 MQTT over TCP | 仅用于经过明确隔离的本地开发环境 |
| 8883 | MQTT over TLS | 生产设备与后端服务 |
| 443 | MQTT over Secure WebSocket | 浏览器,以及仅放行 HTTPS 流量的网络 |
生产客户端应先解析 Broker 域名,建立 TLS 或 WebSocket 传输并校验证书,然后再发送 MQTT CONNECT。TCP 端口可达并不等于 MQTT 连接成功,更不代表连接可信。
随后客户端发送 CONNECT 报文,其中包含:
- 协议版本;
- Client ID;
- Clean Start 与会话设置;
- Keepalive 周期;
- 可选的用户名和密码;
- 可选的遗嘱消息;
- MQTT 5 属性。
Broker 以 CONNACK 响应。连接成功只代表会话已经建立,不代表客户端可以访问所有主题。发布和订阅发生时,Broker 仍需执行授权检查。
同一时刻连接到 Broker 的 Client ID 必须唯一。如果两台设备使用同一个 ID,Broker 通常会断开先建立的会话。生产系统应从稳定的设备身份生成 ID,不要复制示例字符串。
发布订阅如何路由
发布者向一个确定的主题发送 PUBLISH:
factory/shanghai/line-1/motor-7/telemetry
订阅者注册主题过滤器。过滤器可以精确匹配,也可以使用通配符:
factory/shanghai/line-1/+/telemetry
factory/shanghai/#
+ 匹配一个主题层级;# 匹配其后的全部层级,并且只能出现在结尾。宽泛的过滤器适合可信的后端消费者,但通常不应授予现场设备。
主题名属于可见的路由元数据。即使连接已加密,也不要把密码、个人信息或其他敏感内容放进主题名。
QoS 是投递约定,不是质量评分
MQTT 定义了三个 QoS 等级:
| QoS | 投递行为 | 常见场景 |
|---|---|---|
| 0 | 至多一次 | 高频遥测,丢失一条后可由下一条替代 |
| 1 | 至少一次,可能重复 | 状态变化、告警、可幂等处理的指令 |
| 2 | MQTT 协议层恰好一次 | 少数经过验证的恰好一次需求 |
更高的 QoS 会增加报文往返、Broker 状态、客户端状态、带宽和延迟。它也无法保证下游数据库或物理执行器只处理一次业务动作。
对大多数连接型产品,QoS 0 与 QoS 1 已足够覆盖主要工作负载。QoS 1 的消费者应通过消息 ID 或业务操作 ID 实现幂等。
保留消息只保存最新值
发布者设置 Retain 标志后,Broker 会保存该主题最后一条保留消息。新订阅者建立订阅后,会立即收到这个值。
保留消息适合:
- 当前设备状态;
- 最近一次配置;
- 在线或离线状态;
- 新订阅者在下一条实时更新前就需要的值。
它不是通用历史记录。一个主题只保存一个当前保留值,不支持时间线查询。需要历史、分析和重放时,应把事件写入数据库或流式平台。
按照标准行为,向主题发布空的保留载荷可以清除已有保留值。
会话决定断线后保留什么
MQTT 会话可以在客户端断线后保留订阅和排队的 QoS 消息。这对跨网络移动、周期性休眠或网络不稳定的设备非常有用。
设计会话时要回答:
- Client ID 是否稳定?
- Broker 应保留会话多久?
- 设备离线时允许排队哪些 QoS 消息?
- 队列上限是多少?
- 已经过期的指令是否应在重连前丢弃?
MQTT 5 提供明确的会话过期与消息过期设置。两者应配合使用。没有边界的持久会话最终会变成运维负担。
遗嘱消息发现非正常断线
客户端可以在连接时注册 Last Will。如果 Broker 发现客户端没有正常发送 DISCONNECT 就消失,会代替客户端发布遗嘱消息。
常见模式是:
devices/device-042/status = offline
客户端连接成功后发布 online,并把保留的 offline 设置为遗嘱。消费者由此获得更可靠的最后已知在线状态。
遗嘱消息不是瞬时故障检测。发现速度受网络与 Keepalive 影响,安全关键系统仍需在设备本地实现保护逻辑。
值得采用的 MQTT 5 能力
MQTT 5 增加了多项可以减少私有约定的能力:
- 原因码:解释连接、发布和订阅失败。
- 会话过期:区分本次连接是否清理状态,以及状态应保留多久。
- 消息过期:避免过期指令在设备很久以后上线时被投递。
- 主题别名:减少长连接中重复发送主题名的开销。
- 用户属性:在不修改载荷的情况下携带少量元数据。
- 响应主题与关联数据:支持请求响应模式。
- 共享订阅:把匹配消息分发给一组消费者。
只有在 Broker 与客户端设备群都能稳定支持 MQTT 5 时,才应依赖这些能力。不要让旧客户端悄悄降级后破坏业务假设。
上线前检查清单
发布生产系统前:
- 强制使用 TLS 并验证证书;
- 为每台设备签发独立且可撤销的凭证;
- 分离发布与订阅权限;
- 记录主题层级、载荷结构、单位和责任方;
- 根据业务后果选择 QoS;
- 为会话和消息设置过期边界;
- 测试重复投递与重连风暴;
- 监控认证失败、主题拒绝、队列深度和连接抖动。
MQTT 教程会带你完成第一条发布订阅链路;MQTT 安全指南进一步解释传输、身份和主题授权;公共 MQTT Broker只适合合成数据与一次性测试。
