保留消息
本节介绍 MQTT 保留消息(Retained Messages)的工作原理、使用场景和最佳实践。学习完成后,您将能够:
- 理解保留消息的机制和用途
- 在新设备订阅时利用保留消息获取最新状态
- 管理保留消息的生命周期
- 避免保留消息的常见误用
在开始本节之前,请确保:
- 理解 MQTT 消息发布机制
- Mosquitto Broker 已运行
- 已安装 MQTT 命令行工具
什么是 a Retained Message?
Section titled “什么是 a Retained Message?”Definition
Section titled “Definition”保留消息是 Broker 为每个 Topic 存储的最后一条消息。当有新的订阅者订阅该 Topic 时,Broker 会立即将该消息推送给新订阅者。
没有保留消息:Publisher New Subscriber │ │ │─── [发布消息] ──→│ │ │─── [发布消息] ──→│ │ │─── [发布消息] ──→│ │ │ │←── 开始订阅 │ │ 需要等待下一次发布 │ │ │─── [发布消息] ──→│←────── │
有保留消息:Publisher New Subscriber │ │ │─── [发布+保留] ─→│ │ │─── [发布+保留] ─→│ │ │─── [发布+保留] ─→│ │ │ │←── 开始订阅 │ │←── 立即收到保留消息 │ │ (最新状态)How It Works
Section titled “How It Works”# 发布保留消息mosquitto_pub -h localhost -t "devices/status" \ -r -m '{"device": "ESP32_001", "status": "online"}'# -r 标志表示这是一个保留消息
# 新设备订阅(随时订阅)mosquitto_sub -h localhost -t "devices/status" -v# 立即输出: devices/status {"device": "ESP32_001", "status": "online"}Use Cases
Section titled “Use Cases”Primary Use Cases
Section titled “Primary Use Cases”| 用例 | 说明 | 示例 |
|---|---|---|
| 设备状态 | 设备在线/离线状态 | devices/sensor_01/status → "online" |
| 最新传感器值 | 新仪表板立即显示数据 | sensors/temperature → "26.5" |
| 配置信息 | 设备启动时获取配置 | config/device_01 → {"interval": 30} |
| 系统状态 | 系统运行状态 | system/mode → "production" |
Use Case 1: Device Online Status
Section titled “Use Case 1: Device Online Status”// ESP32 连接时发布保留消息void onMQTTConnect() { // 发布在线状态(保留消息) mqttClient.publish("devices/esp32_001/status", "{\"status\":\"online\",\"ip\":\"192.168.1.100\"}", true); // true = retain}
// ESP32 断开时(通过遗嘱消息,见 03-14)// 发布离线状态Use Case 2: Latest Sensor Reading
Section titled “Use Case 2: Latest Sensor Reading”// Node-RED: 发布保留的传感器读数msg.payload = { device: "ESP32_001", temperature: 26.5, humidity: 62, updated_at: Date.now()};msg.retain = true; // 标记为保留消息return msg;Use Case 3: Device Configuration
Section titled “Use Case 3: Device Configuration”// Node-RED: 发布设备配置作为保留消息var config = { sampling_interval: 10, // 秒 temp_threshold: 30, // °C mode: "auto"};
// 发布配置到保留 Topicnode.send({ topic: "config/esp32_001", payload: config, retain: true});Management
Section titled “Management”Clearing Retained Messages
Section titled “Clearing Retained Messages”要清除保留消息,向该 Topic 发送一个空 payload 的保留消息:
# 发布空消息清除保留mosquitto_pub -h localhost -t "devices/sensor_01/status" \ -r -n# -n 表示发送空消息
# 验证清除mosquitto_sub -h localhost -t "devices/sensor_01/status" -v# 如果已是新订阅者,不会收到消息Listing Retained Messages
Section titled “Listing Retained Messages”# 查看所有保留消息(使用特殊的 $SYS Topic)mosquitto_sub -h localhost -t '$SYS/broker/retained messages/count' -v
# 通过 MQTT Explorer 查看保留消息# 保留的消息在界面中会显示一个特殊的"保留"标记Mosquitto Configuration
Section titled “Mosquitto Configuration”# mosquitto.conf - 保留消息配置persistence truepersistence_location /mosquitto/data/
# 保留消息限制# 存储所有 Topic 的保留消息在持久化文件中# 重启后保留消息仍然存在Behavior Characteristics
Section titled “Behavior Characteristics”Retention Scope
Section titled “Retention Scope”保留消息的作用范围:
Topic: sensors/temperature保留消息: "26.5°C"
以下订阅者都会收到保留消息:sensors/temperature ✅ 完全匹配sensors/+ ✅ 单级通配符sensors/# ✅ 多级通配符# ✅ 全局通配符Multiple Retained Messages
Section titled “Multiple Retained Messages”每个 Topic 只能保留一条消息。如果重复发布保留消息:
# 第一次发布mosquitto_pub -h localhost -t "test/retained" -r -m "value1"
# 第二次发布(覆盖)mosquitto_pub -h localhost -t "test/retained" -r -m "value2"
# 新订阅者只会收到最后一次的值mosquitto_sub -h localhost -t "test/retained" -v# 输出: test/retained value2Common Pitfalls
Section titled “Common Pitfalls”Pitfall 1: 过时数据误导
Section titled “Pitfall 1: 过时数据误导”问题:如果设备离线后保留消息仍显示"在线",新订阅者会被误导。
解决方案:1. 结合遗嘱消息在设备离线时自动更新保留消息2. 在保留消息中包含时间戳,让客户端自行判断时效性Pitfall 2: 保留消息滥用
Section titled “Pitfall 2: 保留消息滥用”问题:对所有消息都使用保留标志,导致 Broker 存储膨胀。
解决方案:只对以下类型的消息使用保留:✅ 设备状态(在线/离线)✅ 最新传感器值(可选)✅ 配置信息❌ 高频传感器数据(没必要保留全部)❌ 一次性事件(事件过去后保留无意义)❌ 日志消息(日志不需要保留)验证保留消息行为
Section titled “验证保留消息行为”# 测试步骤 1:发布保留消息mosquitto_pub -h localhost -t "retained/test" -r -m "This is retained"
# 测试步骤 2:新订阅者立即收到mosquitto_sub -h localhost -t "retained/test" -v# 预期立即输出: retained/test This is retained
# 测试步骤 3:覆盖保留消息mosquitto_pub -h localhost -t "retained/test" -r -m "Updated value"
# 测试步骤 4:清除保留消息mosquitto_pub -h localhost -t "retained/test" -r -n
# 测试步骤 5:验证已清除mosquitto_sub -h localhost -t "retained/test" -v# 预期:没有输出(除非有新发布的消息)- ✅ 推荐: 设备状态 Topic 使用保留消息
- ✅ 推荐: 保留消息中包含时间戳,便于判断时效性
- ✅ 推荐: 设备离线时通过遗嘱消息清除或更新保留状态
- ❌ 避免: 对高频变化的数据使用保留消息
- ❌ 避免: 保留消息体过大(建议 < 1KB)
- ❌ 避免: 依赖保留消息作为唯一的数据来源
Summary
Section titled “Summary”本节要点总结:
- 保留消息机制:Broker 存储每个 Topic 的最后一条消息,新订阅者立即收到
- 主要用途:设备状态、最新读数、配置信息
- 生命周期:发布(含 -r 标志)→ 覆盖 → 清除(空 payload + -r)
- 注意事项:过时数据误导、保留消息滥用
- 最佳实践:结合遗嘱消息,包含时间戳,合理选择使用场景