MQTT服务的 Qos 的等级0,1,2

原文链接:http://www.hivemq.com/blog/mqtt-essentials-part-6-mqtt-quality-of-service-levels

转载链接:http://blog.sina.com.cn/s/blog_a5e78d1d0102wqkr.html(对转载文章的翻译进行小修改)

 

什么是Quality of Service

Quality of Service等级是发送与接收端的一种关于保证交付信息的协议。一共有3 个QoS 等级:

  1. 最多一次(0)
  2. 最少一次(1)
  3. 只一次(2)

QoS 总是会有2个不同的交付信息组成:客户端(client)推送给代理(broker),代理(broker)推送给订阅的客户端(client)。因为他们有些微妙的不同,所以我们需要分开的来讲述他们。对于客户端推送给代理的QoS 等级,取决于客户端为某特定信息设定的QoS等级。更直观一点的说就是,当客户端推送信息给代理的时候,QoS的等级是由客户端决定的。当代理传送一条信息给订阅的客户端的时候,会使用这个客户端之前设定的QoS等级。

 

为什么QoS如此重要

 

QoS 是MQTT的一个主要的功能。它使得在一个不稳定的网络环境里的信息交换更加的简单,因为协议控制了中继并保证了信息的交付,忽略了不可靠的下层的交互。并且,它授权给客户端来根据客户端的程序逻辑,网络可靠程度来决定QoS等级。

 

QoS是如何工作的?

那么QoS是如何在MQTT协议中实现的呢?让我们来一个等级一个等级的看一下。

 

QoS 0 —— 最多1次

最小的等级就是 0。并且它保证一次信息尽力交付。一个消息不会被接收端应答,也不会被发送者存储并再发送。这个也被叫做“即发即弃”。并且在TCP协议下也是会有相同的担保。

QoS 1 ——最少1次

当使用QoS 等级1 时, 它保证信息将会被至少发送一次给接受者。但是消息也可能被发送两次甚至更多。


发送者将会存储发送的信息直到发送者收到一次来自接收者的PUBACK格式的应答。


PUBLISH 与PUBACK的关联是通过比较数据包中的packet identifier完成的。如果在特定的时间内(timeout)发送端没有收到PUBACK应答,那么发送者会重新发送PUBLISH消息。如果接受者接收到QoS为1 的消息,它会立即处理这里消息,比如把这个包发送给订阅该主题的接收端,并回复PUBACK包。

 

The duplicate(DUP)flag,用来标记PUBLISH 被重新分发的情况。仅仅是为了内部使用的目的,并且当QoS 为1 是不会被broker 或者client处理。接受者都会发送PUBACK消息,而不管DUP flag。

QoS 2

最高的QoS就是2,它会确保每个消息都只被接收到的一次,他是最安全也是最慢的服务等级。

如果接收端接收到了一个QoS 的PUBLISH消息,它将相应地处理PUBLISH消息,并通过PUBREC消息向发送方确认。


 

直到他发出一个PUBCOMP包为止,接收端都保存这个包packet identifier。这一点很重要,因为它避免了二次处理同一个PUBLISH包。 当发送者接收到PUBREC的时候,它可以放弃最开始的publish了,因为它已经知道另一端已经接收到消息,他将保存PUBREC并且回复PUBREL。

当接收端接收到PUBREL,它就可以丢弃所有该包的存储状态并回复PUBCOMP。当发送端接收到PUBCOMP时也会做同样的处理。

 

当整个流程结束的时候,所有的参与者都确定消息被正确的发送和送达了。

 

无论什么时候,一个包丢失了,发送端有责任在特定时间后重新发送最后一次发送的消息。接收端有责任响应每一个指令消息。

 

须知:

 

QoS 向下兼容

QoS流,在发送端和接收端是两件不同的事情,当然发送端与接收端QoS的等级也可以不一样。在发送端与broker之间,发送端定义了QoS等级。当broker发送消息到接收端是,接收端决定了QoS的等级。 

Packet identifiers 是每个消息流唯一的

在一个client和broker之间,每个packet identiier都是唯一的。如果一个消息流结束了,相同的packet identifier可以在任意时间被重用。这也就是packet identifier没有必要比65535还要大的原因,因为一个client发送如此大的消息去没有结束这个消息流是不切实际的。

 

以下的建议会给你一些指导。通常这很大程度上取决于您的用例。

Best Practice

We are often asked, when to choose which QoS level. The following should provide you some guidance if you are also confronted with this decision. Often this is heavily depending on your use case.

Use QoS 0 when …

  • You have a complete or almost stable connection between sender and receiver. A classic use case is when connecting a test client or a front end application to a MQTT broker over a wired connection.
  • You don’t care if one or more messages are lost once a while. That is sometimes the case if the data is not that important or will be send at short intervals, where it is okay that messages might get lost.
  • You don’t need any message queuing. Messages are only queued for disconnected clients if they have QoS 1 or 2 and a persistent session.

Use QoS 1 when …

  • You need to get every message and your use case can handle duplicates. The most often used QoS is level 1, because it guarantees the message arrives at least once. Of course your application must be tolerating duplicates and process them accordingly.
  • You can’t bear the overhead of QoS 2. Of course QoS 1 is a lot fast in delivering messages without the guarantee of level 2.

Use QoS 2 when …

  • It is critical to your application to receive all messages exactly once. This is often the case if a duplicate delivery would do harm to application users or subscribing clients. You should be aware of the overhead and that it takes a bit longer to complete the QoS 2 flow.

Queuing of QoS 1 and 2 messages

All messages sent with QoS 1 and 2 will also be queued for offline clients, until they are available again. But queuing is only happening, if the client has a persistent session.

<think>好的,用户现在想了解如何在MQTT客户端实现QoS2等级。首先,我需要回忆一下MQTTQoS的不同级别。QoS0是“至多一次”,QoS1是“至少一次”,而QoS2是“恰好一次”,这是最高级别的服务质量,确保消息不重复且可靠传输。 用户之前询问过ESP32官方MQTT SDK的使用,所以可能他们正在使用ESP32进行开发,需要在该平台上实现QoS2。我需要确认ESP32的官方SDK是否支持QoS2,根据之前的对话内容,SDK的关键功能特性里确实提到了支持QoS0/1/2,所以没问题。 接下来,我需要解释QoS2的工作原理。QoS2分为四个步骤:PUBLISH、PUBREC、PUBREL、PUBCOMP。需要详细说明每个步骤的作用,确保用户理解整个流程。 然后,用户可能需要具体的代码示例。在之前的回答中,有给出事件处理回调的代码片段,所以这次也需要提供一个如何在ESP32 SDK中发布和订阅QoS2消息的示例。比如,使用esp_mqtt_client_publish函数时设置qos参数为2,并在订阅主题时同样指定QoS2。 另外,需要强调实现QoS2时的注意事项,比如网络稳定性、消息去重、存储和幂等性处理。这些是实际开发中容易遇到的问题,用户可能想知道如何避免消息重复或丢失,如何处理存储以确保消息状态正确。 用户可能还会关心性能优化,比如QoS2带来的额外开销,以及如何在高延迟或不稳定网络中配置相关参数。需要提到message_retransmit_timeout和max_retransmit_times这样的配置项,帮助用户调整以适应不同环境。 最后,确保回答结构清晰,分点说明,便于用户逐步理解和实施。同时,要提醒用户参考官方文档和示例,特别是在处理消息状态和错误处理时,可能需要更详细的调试和日志记录。</think>以下是MQTT客户端实现QoS2等级的详细技术指南(基于ESP32官方SDK示例): $$ QoS2通信流程 = \text{PUBLISH} \rightarrow \text{PUBREC} \rightarrow \text{PUBREL} \rightarrow \text{PUBCOMP} $$ 1. **QoS2实现原理** - **四步握手机制**:发送方存储消息直到收到PUBCOMP - **消息状态跟踪**:维护`msg_id`与消息的映射关系 - **去重机制**:接收方使用`packet_id`检测重复消息 2. **ESP32 SDK实现步骤** ```c // 发布QoS2消息 int msg_id = esp_mqtt_client_publish(client, "topic/qos2", "payload", 0, 2, 0); // 订阅QoS2主题 esp_mqtt_client_subscribe(client, "topic/qos2", 2); ``` 3. **关键配置参数** ```c esp_mqtt_client_config_t mqtt_cfg = { .message_retransmit_timeout = 5000, // 重传超时(ms) .max_retransmit_times = 3, // 最大重试次数 .outbox_size = 20 // 离线消息缓存容量 }; ``` 4. **状态机处理逻辑** ```c void mqtt_event_handler(...) { switch (event->event_id) { case MQTT_EVENT_DATA: if (event->qos == 2) { handle_qos2_message(event->data, event->data_len, event->msg_id); } break; case MQTT_EVENT_PUBLISHED: if (event->msg_id == stored_msg_id) { // 清除已确认的消息 } } } ``` 5. **必须实现的存储层** - **发送端持久化**:存储未完成QoS2流程的消息(PUBLISH→PUBREC阶段) - **接收端持久化**:存储已接收但未完成确认的消息(PUBREL→PUBCOMP阶段) - 推荐使用Non-Volatile Storage(NVS)实现断电保护 6. **调试QoS2的要点** - 启用`CONFIG_MQTT_PROTOCOL_311`和`CONFIG_MQTT_TRANSPORT_SSL` - 监控消息流: ``` [D][mqtt_client]: Outbox item enqueued, msg_id=15, msg_type=3 [D][mqtt_client]: Sent PUBLISH, msg_id=15 [D][mqtt_client]: Received PUBREC, msg_id=15 [D][mqtt_client]: Sent PUBREL, msg_id=15 [D][mqtt_client]: Received PUBCOMP, msg_id=15 ``` 7. **性能优化建议** $$ \text{理论吞吐量} = \frac{\text{有效载荷}}{\text{往返时间} \times 4} $$ - 增大`CONFIG_MQTT_MAX_PAYLOAD_SIZE`(默认1024字节) - 使用`esp_mqtt_set_config()`动态调整QoS级别 - 启用`CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED` 8. **常见故障处理** | 现象 | 解决方案 | |---|---| | PUBREL超时 | 增大`message_retransmit_timeout` | | 存储空间不足 | 启用`CONFIG_MQTT_OUTBOX_EXPIRED_TIMEOUT` | | 消息重复 | 实现`packet_id`缓存队列(建议环形缓冲区) | 9. **安全增强措施** - 启用TLS加密:`mqtt_cfg.cert_pem = server_cert_pem;` - 使用MQTT 5.0的`User Properties`添加消息指纹 - 实现应用层ACK机制(双重确认) 验证QoS2功能的推荐测试步骤: 1. 发送端断电测试:在PUBREC阶段断电,恢复后应继续流程 2. 接收端断电测试:在PUBREL阶段断电,恢复后应发送PUBCOMP 3. 网络抖动测试:使用tc工具模拟50%丢包率环境 4. 压力测试:连续发送100条QoS2消息验证顺序性 $$ \text{注意事项:QoS2会增加} \approx 40\% \text{的通信开销,建议仅在关键数据通道使用} $$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值