NATS_03:NATS釋出/訂閱機制
釋出/訂閱(Publish/subscribe或pub/sub)是一種訊息正規化,訊息的傳送者(釋出者)不是計劃傳送其訊息給特定的接收者(訂閱者)。而是釋出的訊息分為不同的類別,而不需要知道什麼樣的訂閱者訂閱。訂閱者對一個或多個類別表達興趣,於是只接收感興趣的訊息,而不需要知道什麼樣的釋出者釋出的訊息。這種釋出者和訂閱者的解耦可以允許更好的可擴充套件性和更為動態的網路拓撲.
釋出/訂閱是訊息佇列正規化的兄弟,通常是更大的訊息導向的中介軟體的系統的一部分。大多數訊息系統在應用程式介面(API)中同時支援訊息佇列模型和釋出/訂閱模型,例如Java訊息服務(JMS)。
現實中,並不是所有請求都期待答覆,而不期待答覆,自然就沒有了狀態。廣播聽過吧?收音機用過吧?就這個意思。
釋出/訂閱模式定義了一種一對多的依賴關係,讓多個訂閱者物件同時監聽某一個主題物件。這個主題物件在自身狀態變化時,會通知所有訂閱者物件,使它們能夠自動更新自己的狀態。
訊息過濾
在釋出/訂閱模型中,訂閱者通常接收所有釋出的訊息的一個子集。選擇接受和處理的訊息的過程被稱作過濾。有兩種常用的過濾形式:基於主題的和基於內容的。
在 基於主題 的系統中,訊息被髮布到主題或命名通道上。訂閱者將收到其訂閱的主題上的所有訊息,並且所有訂閱同一主題的訂閱者將接收到同樣的訊息。釋出者負責定義訂閱者所訂閱的訊息類別。
在 基於內容 的系統中,訂閱者定義其感興趣的訊息的條件,只有當訊息的屬性或內容滿足訂閱者定義的條件時,訊息才會被投遞到該訂閱者。訂閱者需要負責對訊息進行分類。
一些系統支援兩者的混合:釋出者釋出訊息到主題上,而訂閱者將基於內容的訂閱註冊到一個或多個主題上。
拓撲
在許多釋出/訂閱系統中,釋出者釋出訊息到一箇中間的 訊息代理,然後訂閱者向該訊息代理註冊訂閱,由訊息代理來進行過濾。訊息代理通常執行 儲存轉發 的功能將訊息從釋出者傳送到訂閱者。
使用場景
很多專案中都有訊息分發或者事件通知機制,尤其是模組化程度高的專案。
比如:在你的系統中,很多模組都對新建使用者感興趣。許可權模組希望給新使用者設定預設許可權,報表模組希望重新生成當月的報表,郵件系統希望給使用者傳送啟用郵件...諸如此類的程式碼都寫到新建使用者的業務邏輯後面,會加大耦合度,降低可維護性,並且對於每個模組都是一個獨立系統的情況,這種方式更是不可取。
對於簡單的情形,觀察者模式The Observer Pattern就足夠了。如果系統中有很多地方都需要收發訊息,那麼它就不適用了。否則會造成類數量的膨脹,增加類的複雜性,這時候就需要一種更集中的機制來處理這些業務邏輯。
特點
一個訂閱者可以訂閱多個釋出者
訊息是會到達所有訂閱者處,訂閱者根據filter丟掉自己不需要的訊息(filter是在訂閱端起作用的)
每個訂閱者都會接收到每條訊息的一個副本
基於推送push,其中訊息自動地向訂閱者廣播,它們無須請求或輪詢主題來獲得新訊息,釋出/訂閱模式內部,有多種不同型別的訂閱者。
非持久訂閱者是臨時訂閱型別,它們只是在主動偵聽主題時才接收訊息。
持久訂閱者將接收到釋出的每條訊息的一個副本,即便在釋出訊息,它們處於"離線"狀態時也是如此。
另外還有動態持久訂閱者和受管的持久訂閱者等型別。
優勢
- 降低了模組間的耦合度:釋出者與訂閱者鬆散地耦合,並且不需要知道對方的存在。相關操作都集中在Publisher中。
- 可擴充套件性強:系統複雜後,可以把訊息訂閱和分發機制單獨作為一個模組來實現,增加新特性以滿足需求
缺陷
與其說缺陷,不如說它設計本身就有如下特點。但不管怎麼說,這種模式在邏輯上不可靠的。主要體現在:
- 釋出者不知道訂閱者是否收到釋出的訊息
- 訂閱者不知道自己是否收到了釋出者發出的所有訊息
- 傳送者不能獲知訂閱者的執行情況
- 沒人知道訂閱者何時開始收到訊息