MQTT 协议深度应用指南
本章目标
从协议原理到生产级部署,全面掌握 MQTT 在物联网系统中的关键设计模式。
1. MQTT 协议核心设计
为什么不用 HTTP?
| 对比 |
HTTP |
MQTT |
| 消息模型 |
请求/响应 |
发布/订阅 |
| 发起方 |
仅客户端 |
双向推送 |
| 开销 |
Header ~800B |
Header 2B (min) |
| 连接保持 |
短连接 |
长连接 |
| 适合设备 |
服务器 |
传感器/嵌入式 |
2. 主题设计最佳实践
推荐层级结构
home/{room}/{device}/{metric}
home/living-room/temperature/state
home/living-room/light/set
home/living-room/light/state
factory/line-1/motor-3/speed
factory/line-1/motor-3/status
device/{device_id}/telemetry
device/{device_id}/command
device/{device_id}/response
设计原则
- 不在主题里放动态值:
sensor/25.5/temp ❌ → sensor/temperature ✅(值放在 payload)
- 使用单数/复数区分:
device/ 放元数据,devices/ 放列表
- 命令用
/set,状态用 /state
3. Broker 选型
| Broker |
特点 |
适合 |
| Mosquitto |
轻量 C 实现,单机百万连接 |
边缘/小规模 |
| EMQX |
Erlang,分布式集群 |
云原生/大规模 |
| VerneMQ |
Erlang,Apache 2.0 |
自建集群 |
| HiveMQ |
Java,企业级 |
商业项目 |
| AWS IoT Core |
托管,与 AWS 生态集成 |
AWS 用户 |
4. 生产部署关键问题
QoS 流控
QoS 1 消息堆积 → Broker 内存暴涨
解决:
1. 限制飞行窗口 (max_inflight_messages)
2. 设置消息过期 (Message Expiry)
3. 监控队列深度 → 告警
遗嘱消息 (LWT) 正确使用
# 连接时设置遗嘱
client.will_set(
"device/status",
json.dumps({"status": "offline", "ts": int(time.time())}),
qos=1,
retain=True
)
# 上线后清除遗嘱状态
client.publish("device/status",
json.dumps({"status": "online"}),
qos=1, retain=True
)
5. 安全架构
设备 (证书) ──TLS──> Broker ──> 应用 (JWT 鉴权)
↑
ACL (按主题授权)
- 设备证书:工厂预烧 X.509
- ACL:
device/{id}/# 只允许该设备访问
- JWT:后端服务用短期 Token
6. 大规模架构
设备 → MQTT Broker (EMQX 集群) → Kafka → Flink/Spark → DB
↓
规则引擎(告警/动作)
思考题
- MQTT 5.0 的共享订阅解决了什么问题?
- 如何设计主题来支持 OTA 固件升级?
- Broker 集群如何保证跨节点的消息顺序?