什么是 QoS ?
QoS (Quality of Service) 是发送者和接收者之间,对于消息传递的可靠程度的协商。安全
QoS 的设计是 MQTT 协议里的重点。做为专为物联网场景设计的协议,MQTT 的运行场景不只仅是 PC,而是更普遍的窄带宽网络和低功耗设备,若是能在协议层解决传输质量的问题,将为物联网应用的开发提供极大便利。网络
三个 QoS 级别简介
在 MQTT 协议里,定义了三个级别的 QoS,由低到高分别是:架构
- 最多一次 (QoS0)
- 至少一次 (QoS1)
- 有且仅有一次 (QoS2)
QoS0 是最低级别,基本上等同于 Fire and Forget
模式,发送者发送完数据以后,不关心消息是否已经投递到了接收者那边。ide
QoS1 是中间级别,保证消息至少送达一次。MQTT 经过简单的 ACK 机制来保证 QoS1。设计
QoS2 是最高级别,保证到且仅到一次。这经过更加复杂的消息流程保证。代理
QoS 级别越高,流程越复杂,系统资源消耗越大。应用程序能够根据本身的网络场景和业务需求,选择合适的 QoS 级别:code
好比在同一个子网内部的服务间的消息交互每每选用 QoS0;而经过互联网的实时消息通讯每每选用 QoS1;QoS2 使用的场景相对少一些,能想到的如国防武器,医疗设备等应用场景。blog
既然 QoS 是发送者和接收者之间的质量协定,在 MQTT 协议的 Client - Broker - Client
架构里,QoS 就须要分红两部分来讨论:资源
- 从发送者到 Broker 之间消息传递的 QoS。这须要由发送者在 MQTT PUBLISH 消息里设置 QoS 级别。
- 从 Broker 到接收者之间消息传递的 QoS。这须要接收者在订阅 Topic 时,设置 SUBSCRIBE 消息里的 QoS 级别。
什么是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发送如此大的消息去没有结束这个消息流是不切实际的。