[Program Note] MQTT QoS(Quality of Service)說明

MQTT的全名為Message Queuing Telemetry Transport,為IBM和Eurotech共同製定的通訊協定,MQTT是為物聯網所設計的M2M通訊協定,網路頻寬與硬體需求非常少,是極為輕便的通訊協定。MQTT通訊協定是基於TCP/IP連線,並提供自有的不同QoS(Quality of Service)層級的訊息傳遞,適用於網路連線不佳的環境、CPU較弱的嵌入式裝置。

MQTT的封包分為三個部分,分別為Fix Header, Variable Header, Payload,在PUBLISH與SUBSCRIBE封包中,QoS會在Fix Header中定義;對於MQTT封包的詳細內容可以參考MQTT官方文件第二章:MQTT Control Packet format。

QoS定義訊息傳送的品質,確保發布的訊息有被確實接收,MQTT定義的QoS分為0、1、2三個等級,在程式撰寫時會在Publisher發送訊息與Subscriber發起訂閱時指定各自的QoS等級:

0:At most once

訊息最多傳送一次,不會確認訊息傳送的結果,不會儲存訊息;如果Subscriber已中斷連線,或如果Broker故障,則該訊息就會會遺失。

在下圖中,Publisher並不能確認Broker是否有收到訊息,同樣的Broker也不能確定Subscriber是否有收到訊息。
2019-01-16_214640.png-MQTT QoS(Quality of Service)說明

1:At least once

一律會傳送訊息至少一次,如果傳送端未接收到確認通知,則會再次傳送訊息並設定DUP(duplicate)旗標,直到接收到確認通知為止。

如下圖,Publisher會在封包Header中加入packet identifier識別碼,訊息發送給Broker之後,Broker會回傳PUBACK(publish acknowledgment) 封包給Publisher,其中也有相同的packet identifier識別碼,讓Publisher確認訊息已經確實送達;同樣的方式也作用在Broker與Subscriber之間。
2019-01-16_214653.png-MQTT QoS(Quality of Service)說明

接收端在處理訊息之後,會從接收端中刪除訊息。如果接收端是Broker,則會將訊息發佈至其Subscriber。如果接收端是Subscriber,則會將訊息遞送至其應用程式。刪除訊息之後,接收端會傳送確認通知至傳送端。

如果發生網路異常,例如Publisher發送訊息後,Broker傳送PUBACK封包時網路出現故障,Publisher在一段時間內沒有收到PUBACK封包,就會認定Broker沒有收到訊息,因而重新傳送一次,在這種狀況下Subscriber就會收到兩次相同的訊息。
2019-01-16_214712.png-MQTT QoS(Quality of Service)說明

2:Exactly once

是最安全但也是最慢的傳送模式。傳送端刪除訊息之前,會在傳送端和接收端之間進行至少兩組傳輸確認機制。

一開始,傳送端會傳送訊息,並取得來自接收端的PUBREC封包;如果傳送端未接收到PUBREC封包,則會再次傳送訊息並設定DUP旗標,直到接收到確認通知為止。

接著,傳送端傳送PUBREL封包通知接收端,接收端會送回PUBCOMP封包確認。如果傳送端未收到PUBCOMP封包,則會再次傳送PUBREL封包,直到收到確認封包為止。在收到PUBCOMP封包之後,傳送端會刪除它已儲存的訊息

如下圖,當Broker收到訊息時會先回覆PUBREC(publish received) 封包,並暫存packet identifier避免重複的訊息;收到PUBREC封包後Publisher會再發送PUBREL(publish release) 封包給Broker,收到PUBREL封包的Broker會回傳PUBCOMP封包給Publisher,此時Publisher才會刪除儲存的訊息;同樣的方式也作用在Broker與Subscriber之間。
2019-01-16_214731.png-MQTT QoS(Quality of Service)說明

對於QoS的應用有個比較特殊的地方,就是當Publisher與Subscriber設定的QoS不同時;Publisher對Broker之間的QoS比較容易理解,就類似一般通訊的交握機制;而Subscriber的QoS可以視為Subscriber要求Broker用指定的QoS層級處理兩者間的訊息傳送。

在訂閱發起的時候,Subscriber會送出要求訂閱的SUBSCRIBE封包給Broker,Broker必須回應一個SUBACK封包,其中會有QoS的回傳碼。QoS的回傳碼會告知這次訂閱被允許的最高QoS等級,或者告知訂閱失敗,並且Broker可能會因為自身的限制,給予比Subscriber所要求還要低的QoS。

而最終Subscriber收到的訊息的QoS,會是由原始Publisher發送訊息QoS與Broker授予的最高QoS兩者間最小的那個來決定;例如,如果Subscriber的QoS為1,如果Publisher的QoS為0,那Broker會以QoS為0的層級傳送訊息給Subscriber,這也代表Subscriber最多只會收到一次訊息,若中間的傳輸出現任何的問題,訊息不會重新傳送。

同樣Subscriber的QoS為1的情況,如果Publisher的QoS為2,那Broker會將Publisher的訊息的QoS降為1再傳送給Subscriber,此時若Subscriber的PUBACK封包沒有確實送達Broker,Broker就會認為訊息傳送失敗而重新傳送,Subscriber就會收到重複的訊息。

而當Subscriber的QoS為2時,依照之前所說的:「Subscriber收到的訊息的QoS,會是由原始Publisher發送訊息QoS與Broker授予的最高QoS兩者間最小的那個來決定」,此時收到訊息的QoS會由Publisher來決定,也就是說這代表的意思為:「我要依照Publisher的QoS,接受符合Topic的訊息」。

下表將Publisher與Subscriber在不同的QoS組合下,所可能產生的Subscriber收到的訊息的QoS列出,在設定程式QoS時可參考此表選擇合適的QoS。
Publisher QoS
Subscriber QoS
Overall QoS
0
0或1或2
0
1
0
0
1
1或2
1
2
0
0
2
1
1
2
2
2

留言