天天看點

共享訂閱--MQTT 5.0新特性

作者:EMQ映雲科技

前言

共享訂閱是MQTT 5.0協定引入的新特性,相當于訂閱端的負載均衡功能。

一般的非共享訂閱的消息釋出流程是這樣的:

共享訂閱--MQTT 5.0新特性

在這種結構下,如果訂閱節點發生故障,就會導緻釋出者的消息丢失(QoS 0)或者堆積在Server中(QoS 1,2)。一般情況下,解決這個問題的辦法都是直接增加訂閱節點,但這樣又産生了大量的重複消息,不僅浪費性能,在某些業務場景下,訂閱節點還需要自行去重,進一步增加了業務的複雜度。

其次,當釋出者的生産能力較強時,可能會出現訂閱者的消費能力無法及時跟上的情況,此時隻能由訂閱者自行實作負載均衡來解決,又一次增加了使用者的開發成本。

協定規範

現在,在MQTT 5.0協定中,你可以通過共享訂閱特性解決上面提到的問題。當你使用共享訂閱時,消息的流向就會變為:

共享訂閱--MQTT 5.0新特性

同非共享訂閱一樣,共享訂閱包含一個主題過濾器和訂閱選項,唯一的差別在于共享訂閱的主題過濾器格式必須是$share/{ShareName}/{filter}這種形式。這幾個的字段的含義分别是:

  • $share 字首表明這将是一個共享訂閱
  • {ShareName}是一個不包含"/","+"以及"#"的字元串。訂閱會話通過使用相同的 {ShareName}表示共享同一個訂閱,比對該訂閱的消息每次隻會釋出給其中一個會話
  • {filter}即非共享訂閱中的主題過濾器

需要注意的是,如果服務端正在向其選中的訂閱端發送QoS 2消息,并且在分發完成之前網絡中斷,服務端會在訂閱端重新連接配接時繼續完成該消息的分發。如果訂閱端的會話在其重連之前終止,服務!端将丢棄該消息而不嘗試發送給其他訂閱端。如果是QoS 1消息,服務端可以等訂閱端重新連接配接之後繼續完成分發,也可以在訂閱端斷開連接配接時就立即嘗試将消息分發給其他訂閱端,MQTT協定沒有強制規定,是以需要視伺服器的具體實作而定。但如果在等待訂閱端重連期間其會話終止,服務端則會将消息嘗試發送給其他訂閱端。

共享政策

雖然共享訂閱使得訂閱端能夠負載均衡地消費消息,但MQTT協定并沒有規定Server應當使用什麼負載均衡政策。作為參考,EMQX提供了random,round_robin,sticky,hash四種政策供使用者自行選擇。

  • random:在所有共享訂閱會話中随機選擇一個發送消息
  • round_robin:按照訂閱順序輪流選擇
  • sticky:使用random政策随機選擇一個訂閱會話,持續使用至該會話取消訂閱或斷開連接配接再重複這一流程
  • hash:對發送者的Client ID進行hash操作,根據hash結果選擇訂閱會話

效果示範

最後,我們通過一個綜合性的示例來示範共享訂閱的效果。

服務端使用emqx-v3.2.4,用戶端使用emqtt,emqx的共享訂閱分發政策為預設的random:broker.shared_subscription_strategy=random

使用./emqxstart 啟動emqx,然後使用emqtt啟動三個訂閱用戶端,分别訂閱 $share/a/topic, $share/a/topic, $share/b/topic

共享訂閱--MQTT 5.0新特性

啟動一個釋出用戶端,向topic主題釋出消息。

共享訂閱--MQTT 5.0新特性

$share/a/topic 與$share/b/topic屬于不同的會話組,非共享訂閱主題topic會在所有的會話組中進行負載均衡。用戶端sub3因為組内隻有自己一個會話,是以收到了所有消息,而用戶端sub1與sub2則是遵循我們配置的random政策随機接收消息。