什麼是 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發送如此大的消息去沒有結束這個消息流是不切實際的。