MQTT Part 2 發布和訂閱

本文翻譯自http://www.hivemq.com/blog/mqtt-essentials-part2-publish-subscribe

未經允許,不得轉載

發布/訂閱模式

發布/訂閱(pub/sub)模式是傳統的客戶端-服務器模式的一種替代方案。我們將發送數據的客戶端稱之為發布者,將接收數據的客戶端稱為訂閱者,發布/訂閱模式將這些客戶端進行解耦。這意味著發布者和訂閱者互相不知道對方的存在,在其之間存在一個第三方組件,我們稱之為中間人(broker),發布者和訂閱者只與中間人進行通信。中間人可以過濾收到的信息,并對其進行相應的分發。下面讓我們對其進行更進一步的了解,這只是發布/訂閱模式的基礎部分,稍后我們將探討更多細節。



正如上面提到的,發布/訂閱模式可以將發布者和訂閱者在多個維度進行解耦:

  • 空間解耦:發布者和訂閱者不需要互相知道對方的存在,例如對方的ip地址,端口號等。
  • 時間解耦:發布者和訂閱者不需要同時運行。
  • 同步解耦:在發布和訂閱消息時,雙方的運作無需中斷。

總之,發布/訂閱模式解耦了發布者和訂閱者,通過消息過濾使得某個客戶端只接受某個消息得以實現。解耦從三個維度展開:空間上、時間上和同步上。

擴展性

相較于傳統的客戶端-服務器模式,發布/訂閱模式還提供了更好的擴展性。這是因為在broker上的操作可以高度并行處理。消息緩存和智能路由在提高可擴展性上起了決定性作用。但百萬級的連接量對發布/訂閱模式仍然是個挑戰,這可以通過集群式的broker節點來實現,借助負載均衡器可以將單個的服務器的壓力進行分攤。(我們會用單獨的一章來介紹此內容,其目前超越了我們的討論范圍)

消息過濾

令人感興趣的是,broker是怎樣過濾消息的,如何使訂閱者只接受到其感興趣的消息?

選擇1:基于主題過濾

主題是消息體的一部分,接收端通過在broker上訂閱其感興趣的主題,以獲取所有關于此主題的全部消息。主題是具有分層結構的普通字符串,其允許過濾器基于有限數量的表達式進行過濾。

選擇2:基于內容過濾

正如其名,基于內容過濾即broker基于特定的內容進行過濾。broker通過查詢消息來提供給訂閱者其感興趣的消息內容。這種方式的一大弊端就是消息內容必須被預知并且不能被加密,也不能被輕易改動。

選擇3:基于類型過濾

當采用面向對象語言時,基于消息或事件的類型(type)或類(class)進行過濾是一種常見方案。在這種情況下,訂閱者可以監聽所有來自此類或其子類的消息。

當然了,發布/訂閱模式也不是萬能的,在使用它之前,還要考慮一些事情。解耦發布者和訂閱者是發布/訂閱模式的關鍵,這也為其帶來一些難點。你必須預知所發布消息的結構。在基于主題過濾的情況下,發布者和訂閱者需要知道正確的主題。在分發消息方面,發布者并不知道有誰在接受其所發布的消息,所以可能某些消息永遠都不會有訂閱者。

MQTT

現在我們學習了發布/訂閱模式的基本內容,但MQTT與其有什么關系?MQTT采用的即是發布/訂閱模式,實現了我們上文提到的所有方面,就看你怎么使用它了。MQTT也解耦了發布者和訂閱者,所以我們只需要知道broker的主機IP地址和端口號,即可實現發布訂閱消息。它同樣在時間上實現了解耦,但這是種低效運行方案,因為大部分使用場景都需要近乎實時地分發消息。當然,broker也可以在客戶端不在線時緩存消息。(這需要滿足兩個前提條件:客戶端曾連接過一次,并且會話是持久的,而且其以高于0的服務質量級別的方式訂閱過相應的主題)。MQTT同樣可以在同步上進行解耦,大部分客戶端庫都是異步實現的,采用回調或類似機制。所以其在發布和訂閱消息時不會干擾其他任務。但某些情況下采用同步方案效果也不錯,所以某些庫也支持同步API來等待消息。但是通常情況下,數據流都是異步的。另一個需要提及的重點是MQTT在客戶端實現起來非常容易。不同的發布/訂閱系統的broker有不同的實現邏輯,但客戶端的解決方案都一樣,只需要導入客戶端的庫文件即可實現,這是非常適合小型的資源受限的設備使用的輕量級協議。

MQTT采用基于主題的消息過濾方式,所以每個消息都需要包含一個主題以便于broker識別,進而也決定了訂閱者是否能收到這條消息。HiveMQ broker也可以通過自定義插件來實現基于內容的過濾方式。

為了更好的使用發布/訂閱模式,MQTT定義了一個服務質量(QoS)級別,借此可以很容易的指定broker和客戶端消息收發成功率級別。對于某些主題無人訂閱的情況,broker如何處理這種情況可以決定這是否是一個問題。例如HiveMQ broker有一個插件系統,能夠識別這種情況并加以處理,或者僅將其寫入數據庫日志以供歷史分析。為了規避主題變動的風險,小心設計主題樹,并為以后的擴展留足空間十分重要。如果你采用了這種策略,MQTT將會是完美的產品解決方案。

和消息隊列的區別

MQTT存在一些讓人容易混淆的地方,例如他的名字以及它是否采用的是消息隊列的方式。現在讓我們將其解釋清楚,上一章節我們提到過MQTT的名字和消息隊列(message queue)沒有任何關系,但是除卻名字不提,MQTT和傳統的消息隊列模式有什么不一樣呢?

消息隊列會存儲消息直到其被消費
當使用消息隊列時,每一個入隊消息都會被存儲起來,直至其被其他客戶端取出(我們常稱之為消費)。否則,消息將會被卡在消息隊列中一直等待著被消費。消息不能不被任何客戶端處理,這有點像在MQTT中無人訂閱的一個主題。

一個消息只會被一個客戶端消費
另一個較大的不同是傳統的消息隊列中的一個消息只能被一個客戶端消費,所有的客戶端以分布式的方式處理同一個消息隊列。在MQTT中正好相反,每一個訂閱者都可以收到其訂閱的主題消息。

隊列需要被明確地命名
一個隊列比一個主題要固定的多,在使用隊列之前,必須使用一個特定的命令來創建隊列,只有這樣它才能發布和消費消息。而MQTT的主題要靈活的多。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容