MQTT V3.1----flow


該文章轉自:聶永的博客(http://www.blogjava.net/yongboy/archive/2014/02/15/409893.html)


 

 

網絡故障

在任何網絡環境下,都會出現一方連接失敗,比如離開公司大門那一刻沒有了WIFI信號。但持續連接的另一端-服務器可能不能立即知道對方已斷開。類似網絡異常情況,都有可能在消息發送的過程中出現,消息發送出去,就丟失了。

MQTT協議假定客戶端和服務器端穩定情況一般,彼此之通信管道不可靠,一旦客戶端網絡斷開,情況就會很嚴重,很難恢復原狀。

但別忘記,很多客戶端會有永久性存儲設備支持,比如閃存ROM、存儲卡等,在通信出現異常的情況下可以用於保存關鍵數據或狀態信息等。

總之,異常網絡情況很復雜,只能小心處理之。

消息重發策略

QoS > 0情況下,PUBLISH、PUBREL、SUBSCRIBE、UNSUBSCRIBE等類型消息在發送者發送完之后,需要等待一個響應消息,若在一個指定時間段內沒有收到,發送者可能需要重試。重發的消息,要求DUP標記要設置為1.

等待響應的超時應該在消息成功發送之后開始算起,並且等待超時應該是可以配置選項,以便在下一次重試的時候,適當加大。比如第一次重試超時10秒,下一次可能為20秒,再一次重試可能為60秒呢。當然,還要有一個重試次數限制的。

還 有一種情況,客戶端重新連接,但未在可變頭部中設置clean session標記,但雙方(客戶端和服務器端)都應該重試先前未發送的動態消息(in-flight messages)。客戶端不被強制要求發送未被確認的消息,但服務器端就得需要重發那些未被去確認的消息。

QoS level決定的消息流

QoS level為Quality of Service level的縮寫,翻譯成中文,服務質量等級。

MQTT 3.1協議在"4.1 Quality of Service levels and flows"章節中,僅僅討論了客戶端到服務器的發布流程,不太完整。因為決定消息到達率,能夠提升發送質量的,應該是服務器發布PUBLISH消息到訂閱者這一消息流方向。

QoS level 0

至多發送一次,發送即丟棄。沒有確認消息,也不知道對方是否收到。

Client

Server
QoS = 0 PUBLISH
---------->
Action: Publish message to subscribers then Forget
Reception: <=1

針對的消息不重要,丟失也無所謂。

網絡層面,傳輸壓力小。

QoS level 1

所有QoS level 1都要在可變頭部中附加一個16位的消息ID。

SUBSCRIBE和UNSUBSCRIBE消息使用QoS level 1。

針對消息的發布,Qos level 1,意味着消息至少被傳輸一次。

發送者若在一段時間內接收不到PUBACK消息,發送者需要打開DUB標記為1,然后重新發送PUBLISH消息。因此會導致接收方可能會收到兩次PUBLISH消息。針對客戶端發布消息到服務器的消息流:

Client

Server
QoS = 1
DUP = 0
Message ID = x

Action: Store message

PUBLISH
---------->
Actions:
  • Store message

  • Publish message to subscribers
  • Delete message

Reception: >=1
Action: Discard message PUBACK
<----------
Message ID = x

針對服務器發布到訂閱者的消息流:

Server

Subscriber
QoS = 1
DUP = 0
Message ID = x
PUBLISH
---------->
Actions:
  • Store message

  • Make message available                       
Reception: >=1
  PUBACK
<----------
Message ID = x

發 布者(客戶端/服務器)若因種種異常接收不到PUBACK消息,會再次重新發送PUBLISH消息,同時設置DUP標記為1。接收者以服務器為例,這可能 會導致服務器收到重復消息,按照流程,broker(服務器)發布消息到訂閱者(會導致訂閱者接收到重復消息),然后發送一條PUBACK確認消息到發布 者。

在業務層面,或許可以彌補MQTT協議的不足之處:重試的消息ID一定要一致接收方一定判斷當前接收的消息ID是否已經接受過

但一樣不能夠完全確保,消息一定到達了。

QoS level 2

僅僅在PUBLISH類型消息中出現,要求在可變頭部中要附加消息ID。

級別高,通信壓力稍大些,但確保了僅僅傳輸接收一次。

先看協議中流程圖,Client -> Server方向,會有一個總體印象:

Client

Server
QoS = 2
DUP = 0
Message ID = x

Action: Store message

PUBLISH
---------->
Action(a) Store message

or

Actions(b):
  • Store message ID
  • Publish message to subscribers
  PUBREC
<----------
Message ID = x
Message ID = x PUBREL
---------->
Actions(a):
  • Publish message to subscribers
  • Delete message

or

Action(b): Delete message ID
Action: Discard message PUBCOMP
<----------
Message ID = x

Server -> Subscriber

Server

Subscriber
QoS = 2
DUP = 0
Message ID = x
PUBLISH
---------->
Action: Store message
  PUBREC
<----------
Message ID = x
Message ID = x PUBREL
---------->
Actions:
  • Make message available                       
  PUBCOMP
<----------
Message ID = x

Server 端采取的方案a和b,都包含了何時消息有效,何時處理消息。兩個方案二選一,Server端自己決定。但無論死采取哪一種方式,都是在QoS level 2協議范疇下,不受影響。若一方沒有接收到對應的確認消息,會從最近一次需要確認的消息重試,以便整個(QoS level 2)流程打通。

消息順序

消息順序會受許多因素的影響,但對於服務器程序,必須保證消息傳遞流程的每個階段要和開始的順序一致。例如,在QoS level 2定義的消息流中,PUBREL流必須和PUBLISH流具有相同的順序發送:

Client

Server
  PUBLISH 1
---------->
PUBLISH 2
---------->
PUBLISH 3
---------->
 
  PUBREC 1
<----------
PUBREC 2
<----------
 
  PUBREL 1
---------->
 
  PUBREC 3
<----------
 
  PUBREL 2
---------->
 
  PUBCOMP 1
<----------
 
  PUBREL 3
---------->
 
  PUBCOMP 2
<----------
PUBCOMP 3
<----------
 

流動消息(in-flight messages)數量允許有一個可保證的效果:

  • 在流動消息(in-flight)窗口1中,每個傳遞流在下一個流開始之前完成。這保證消息以提交的順序傳遞
  • 在流動消息(in-flight)大於1的窗口,只能在QoS level內被保證消息的順序

消息的持久化

在MQTT協議中,PUBLISH消息固定頭部RETAIN標記,只有為1才要求服務器需要持久保存此消息,除非新的PUBLISH覆蓋。

對於持久的、最新一條PUBLISH消息,服務器不但要發送給當前的訂閱者,並且新的訂閱者(new subscriber,同樣需要訂閱了此消息對應的Topic name)會馬上得到推送。

Tip:新來乍到的訂閱者,只會取出最新的一個RETAIN flag = 1的消息推送,不是所有。

 

小結

mqtt的消息流,以小和輕量為主要目標,QoS級別進行了消息傳輸的保證。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM