跳转到内容

QoS 0(最多一次)

本节介绍 MQTT QoS 0(最多一次送达)的工作原理、使用场景和技术实现。学习完成后,您将能够:

  • 理解 QoS 0 的消息传递机制
  • 确定哪些场景适合使用 QoS 0
  • 在 Node-RED 和 ESP32 中配置 QoS 0
  • 解释不同 QoS 级别的选择理由

在开始本节之前,请确保:

  • 理解 MQTT 协议基础
  • Mosquitto Broker 已运行
  • 已安装 MQTT 命令行工具

QoS 0(At most once,最多一次)是 MQTT 中最基础的 QoS 级别,提供”尽力而为”的消息投递。

核心特点

  • 发送者只发送一次消息
  • 不需要任何确认(ACK)
  • 不重试失败的消息
  • 不存储消息状态
Publisher Broker Subscriber
│ │ │
│─── PUBLISH ──────────→│ │
│ (QoS=0, no ID) │ │
│ │─── PUBLISH ──────────→│
│ │ (QoS=0, no ID) │
│ │ │
│ ✗ No acknowledgement │ │
│ ✗ No retry │ ✗ No acknowledgement│
│ ✗ No state stored │ ✗ No retry │
│ │ │

协议层面

  • 发布者发送 PUBLISH 报文(QoS=0,不包含 Packet ID)
  • 发布者发送后立即丢弃该消息的状态
  • Broker 接收后转发给订阅者
  • 订阅者接收消息但不发送确认
  • 任何环节失败→消息丢失
指标QoS 0对比其他级别
消息头开销最小(2 字节)QoS 1: 4 字节
网络往返0 次QoS 1: 1 次
消息丢失率可能(但低)Q0S 1: 极低
消息重复率QoS 1: 可能
发布者资源最低QoS 1: 需要存储
Broker 资源最低QoS 1: 需要存储
可能的消息丢失场景:
1. 发布者到 Broker 网络中断
Publisher ──✗──→ Broker
消息在传输中丢失,发布者不知情
2. Broker 转发失败
Broker ──✗──→ Subscriber
订阅者未收到消息,Broker 不重试
3. 订阅者离线
订阅者在消息到达时不在线
消息不被存储(非持久会话)
4. Broker 崩溃
内存消息丢失(无持久化)
场景推荐 QoS理由
高频传感器数据(1 秒/次)QoS 0丢失一条无关紧要,下次有更新
无线遥测数据QoS 0低带宽、高性能需求
位置更新(GPS)QoS 0旧数据没用,需要最新值
日志/调试消息QoS 0丢失不影响系统运行
非关键状态通知QoS 0偶尔丢失可接受
场景推荐 QoS理由
设备控制命令QoS 1/2控制命令不能丢失
支付交易消息QoS 2必须精确一次
告警通知QoS 1告警不可丢失
配置更新QoS 1配置需要可靠到达
设备固件更新QoS 1关键操作
#include <PubSubClient.h>
// 使用 QoS 0 发布传感器数据
void publishSensorData(float temperature, float humidity) {
char payload[64];
snprintf(payload, 64,
"{\"temp\":%.1f,\"hum\":%.1f}",
temperature, humidity);
// publish 的第三个参数是 QoS,第四个是 retain
// publish(topic, payload, length, retained)
boolean result = mqttClient.publish(
"sensors/environment",
payload,
false // QoS 0
);
if (result) {
Serial.println("Published with QoS 0");
} else {
// QoS 0 下失败通常表示连接已断开
Serial.println("Publish failed - connection issue");
}
}
// 配置 QoS 0 订阅
void setupMQTT() {
mqttClient.setServer(MQTT_BROKER, 1883);
mqttClient.setCallback(callback);
mqttClient.connect("esp32_client");
// subscribe 的第二个参数是 QoS
// subscribe(topic, qos)
mqttClient.subscribe("sensors/control", 0); // QoS 0
}
Node-RED MQTT In 节点配置:
├── Server: [MQTT Broker]
├── Topic: sensors/environment
├── QoS: 0 (At most once) ← 选择
├── Output: a parsed JSON object
└── Name: Environment Data
MQTT Out 节点配置:
├── Server: [MQTT Broker]
├── Topic: sensors/control
├── QoS: 0 (At most once) ← 选择
├── Retain: false
└── Name: Control Command
Terminal window
# 发布 QoS 0 消息(默认)
mosquitto_pub -h localhost -t "test/qos0" -m "hello" -q 0
# 订阅 QoS 0
mosquitto_sub -h localhost -t "test/qos0" -q 0
# 验证 - 查看 Broker 日志的输出
docker logs mosquitto --tail 10
场景QoS 0QoS 1QoS 2
消息延迟 (局域网)< 1ms1-2ms3-5ms
消息吞吐量 (1k payload)~50,000/s~20,000/s~8,000/s
带宽开销 (per msg)2 字节~6 字节~12 字节
CPU 占用
内存占用无状态存储消息直到确认完整的握手状态
  • 推荐: 在高频传感器数据场景默认使用 QoS 0
  • 推荐: 配合保留消息使用,保证新订阅者获得最新值
  • 推荐: 在稳定的有线网络环境中放心使用
  • 避免: 关键控制命令使用 QoS 0
  • 避免: 在不可靠的移动网络中使用 QoS 0
  • 避免: 期望 QoS 0 保证消息投递的可靠性
Terminal window
# 测试步骤
# 终端 1: 以 QoS 0 订阅
mosquitto_sub -h localhost -t "qos0/test" -q 0 -v
# 终端 2: 以 QoS 0 发布
mosquitto_pub -h localhost -t "qos0/test" -q 0 -m "QoS 0 message"
# 验证: 订阅者接收消息
# 验证: 消息丢失时不重试

Q: 传感器数据丢失了怎么办?

A: 我们的温度传感器每 3 秒发送一次数据。如果某次数据丢失,3 秒后就会收到新的数据。对于环境监测来说,丢失一个数据点不会影响整体趋势的判断。如果需要更高的可靠性,可以为关键传感器设置 QoS 1。

Q: 为什么不在所有场景都用最高可靠性?

A: 更高的可靠性意味着更多的网络流量和处理延迟。对于几秒钟就更新一次的传感器数据,使用 QoS 0 可以减少 90% 的网络开销,同时不会对监控效果产生明显影响。

本节要点总结:

  1. QoS 0 定义:最多一次送达,发送后不确认、不重试
  2. 可靠性:最低,消息可能丢失
  3. 性能:最佳,零额外网络开销
  4. 适用场景:高频传感器数据、非关键遥测、调试日志
  5. 不适用场景:控制命令、告警通知、支付交易