原文链接: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 等级:
- 最多一次(0)
- 最少一次(1)
- 只一次(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.