編譯 | 朱先忠
策劃 | Ethan
日常開發中,我們通常會在同一個體系架構中部署了多個不同角色的應用程序,而這些應用程序需要某種機制來通知彼此發生了哪些事件。這些事件可能是臨時的(在運行時臨時所做的更改),也可能是數據庫事件(由于數據庫中的更改)。如何應對這種復雜多變的分布式事件,一直是件相當棘手的問題。而這正是發布-訂閱設計模式的用武之地。
眾所周知,發布-訂閱模式在眾多設計模式中,可能是最常見、最有名的一個了。它定義了一種一對多的關系,讓多個訂閱者對象同時監聽某一個主題對象,當這個主題對象的狀態發生變化時就會通知所有訂閱自己的訂閱者對象,使得他們能夠自動更新自己。
在“發布-訂閱”的消息傳遞范式中,消息的發送者(發布者)并不知道預期的收件人(訂閱者)。此外,發布者和訂閱者應用程序之間并不直接交互,而是依賴于稱為“主題”的公共媒體。因此,發布-訂閱模式是一個松散耦合的消息傳遞cdxxd模型。
正是基于這些特性,發布-訂閱模式(簡稱為“發布/訂閱”)成為了構建企業級.NET應用程序不可或缺的工具。
分布式事件驅動架構探索
為了設計分布式事件驅動體系架構,開發人員以往傾向于采用以下方案之一。
1、RDBMS提供數據通知
如果數據存儲僅限于關系數據庫,數據庫通知功能的確可以做到。除了允許向數據庫服務器注冊事件外,該功能還會在數據庫結果集因更新、添加或刪除而發生更改時,通知到應用程序側。
但這里有一個問題,RDBMS本質上是不可擴展的,很容易成為應用程序的性能瓶頸。典型情況下,開發者不想讓數據庫承擔不必要的額外任務。此外,數據庫通知功能本身速度也較慢,而且不支持運行時數據共享。
這就不難理解,將數據庫用作消息傳遞介質并不是最佳設計選擇。
2、消息隊列
另一種選擇是在體系架構中引入單獨的消息隊列。雖然這些消息隊列在幫助您在應用程序之間傳輸消息方面做得很好,但這些隊列并不是以數據為中心的,即它們不監視數據庫或任何其他源中的數據更改。此外,這些消息隊列無法與應用層一起擴展。
3、自定義解決方案
剩下的最后一個選擇是,打造適合自己需要的消息平臺。定制解決方案這個想法乍一看很誘人,但是在所需的時間和資源方面都可能難以預估,因為構建和管理一個健壯且可擴展的消息傳遞平臺是一項非常艱巨的任務。
問題癥結在于:究竟哪種解決方案更易于合并、可擴展、高可用且非??煽???
以分布式緩存作為消息傳遞平臺
這里分享一種使用分布式緩存消息傳遞平臺NCache。事實證明,這不僅是一個簡單可行的解決辦法,而且也是整合健壯消息傳遞平臺的一種更現代化的方法。NCache是目前市場上提供的唯一真正的本地.NET/.NET內核分布式緩存。它是一種內存中的分布式緩存技術,速度極快,可擴展性極強。它使應用程序能夠處理極端的事務負載,而不會使數據庫成為瓶頸。此外,您還可以使用NCache以實時方式來處理數據/流。
NCache通常部署在N層體系架構的中間層。下圖給出其所在架構層次的更直觀的展示。
圖1:N層體系架構中部署的NCache
NCache是一個緩存服務器集群,能夠每秒為.NET應用以及Java應用提供數萬個請求——通過將經常使用的數據保存在內存中,從而有效避免大量的數據庫訪問。
下面,深入分析一下NCache。首先,讓我們看看NCache作為事件驅動體系架構的消息總線的原理。
1、NCache事件驅動消息
下圖顯示了NCache是如何作為.NET和Java應用程序的消息總線功能的。
圖2:NCache作為消息傳遞平臺
在上圖架構中,NCache通過使用快速緊湊序列化來實現跨平臺通信,該序列化可以轉換.NET或Java對象轉換為二進制文件,然后將它們傳輸到緩存集群。所以,這就給出了NCache如何支持.NET應用程序與Java應用程序進行交互的內在邏輯。有關這方面更多信息,請自行搜索查看可移植的數據類型相關內容。
NCache以事件的名稱管理發布/訂閱設計模式,并提供不同的方法將消息傳播到其他偵聽應用程序。讓我們看看這兩種消息類型,從而了解分布式緩存是如何傳播它們的。
首先,考慮應用程序需要偵聽的數據變化。因為NCache也是使用.NET鍵值存儲技術,它提供在緩存中發生任何數據變化時更新應用程序的功能。因為所有這些都發生在內存中,所以不存在性能瓶頸問題。這些數據變化可以是:
- 緩存級項目變化,無論是更新還是刪除
- 整個緩存級數據變化
- 連續查詢,您可以在其中注冊一個類似SQL的查詢,以監視結果集是否在緩存中更改。如果確實如此,則會通知應用程序
- 如果由于任何新節點添加或刪除或崩潰導致的集群發生更改。(對于管理方面來說)
NCache還允許數據庫的依賴關系注冊,包括SQL、Oracle和OleDb等。這有助于使數據庫以及應用程序的緩存數據保持最新。有關支持的依賴關系類型的完整列表,請檢查數據庫依賴關系內容,在此不再贅述。這些依賴項是在不同的數據存儲中注冊的數據變化通知;但是,可以讓NCache處理它。您還可以將數據庫通知與NCache數據通知相結合,以便進一步豐富項目構建策略。
另一方面,如果您只想將簡單消息傳播到復雜的.NET或Java對象,那么你應該使用自定義消息傳遞功能。在這里,一個應用程序可以生成數據并觸發事件,而感興趣的偵聽器幾乎會在瞬間接收到事件。有關這方面的更多信息,讀者可以自行查看自定義事件相關的文章。
2、NCache發布/訂閱API
NCache提供了內存發布者/訂閱者(發布/訂閱)功能和專用的發布/訂閱消息存儲,以支持.NET Web應用程序中的實時信息共享,最終幫助應用程序更好地通信。
發布/訂閱模式通過提供一個由感興趣的用戶發布和訂閱消息的渠道,自然地將發布者和訂閱者解耦?,F在,當NCache充當消息傳遞總線時,發布/訂閱模型受益于底層NCache分布式體系架構和許多方便的功能。
3、基本架構
先來了解一下NCache發布/訂閱的基本組件及其工作原理。NCache發布/訂閱消息的一般流程如下:首先,由發布者使用ITopic接口發布主題消息。接下來,訂閱者可以創建對一個或多個主題的訂閱,并接收相關消息。成功傳遞消息后,NCache將收到確認;否則,NCache將在消息過期之前繼續重試(如果設置了過期信息)。未送達的消息將駐留在緩存中,直到過期消息被觸發,請參考下圖示意。
圖3:NCache發布/訂閱消息機制
4、訂閱類型
NCache為發布/訂閱消息提供了兩種不同類型的訂閱,即非持久訂閱和持久訂閱。此外,NCache支持獨占和共享訂閱策略。下文將討論相關細節。
- 非持久訂閱:默認情況下,在主題上創建的所有訂閱都是非持久訂閱。它僅在保持連接之前將預期消息傳送給訂閱者。如果訂閱者的連接因任何原因而丟失,則不會在重新加入網絡時收到舊消息。這種類型的訂閱是獨占的,這意味著一個訂閱僅屬于一個訂閱者
- 持久訂閱:它考慮了訂閱者斷開連接時的消息丟失。NCache在連接丟失時保留訂閱者的訂閱。因此,訂閱者可以在重新連接時接收其所發布的感興趣的消息
持久訂閱提供了兩種策略:
- 獨占式:一次一個訂閱僅屬于一個活動的訂閱方
- 共享式:一個訂閱可以同時注冊多個訂閱者,并提供負載共享
NCahce發布/訂閱應用案例
假設有一家電子商務商店,不同供應商定期向該商店提供新產品。同時,還提供產品的銷售和優惠。對所提供產品感興趣的門店經理和客戶需要隨時了解新產品、待售產品和折扣的最新情況。NCache發布/訂閱功能可以在此場景中啟用分布式通知系統。為此,可以首先創建NCache專用的發布/訂閱消息存儲。
接下來,讓我們討論一下在上述場景中通過使用NCache發布/訂閱消息API實現分布式消息的逐步過程。
1、創建主題
作為第一步,需要創建一個主題,以便不同供應商可以發布新產品的更新??梢允褂肗Cache中的ITopic接口創建一個具有唯一名稱的新主題。下面的代碼展示了發布方應用程序如何使用方法CreateTopic來創建一個名為newProducts的主題。
//前提條件:緩存已連接
//指定主題名稱
string topicName = “newProducts”
//創建主題
ITopic topic = cache.MessagingService.CreateTopic(topicName);
如果已經存在具有所提供名稱的主題,則該主題的實例將作為ITopic返回。
NCache允許在創建主題時設置主題優先級。當某些事件需要以比其他事件更高的優先級進行溝通時,這很有用。例如,有關制成品的信息就是很緊急的;同樣,由于折扣或銷售導致的產品價格更新對于賣方/買方來說也是最重要的。在這種情況下,可以在創建主題時將主題優先級設置為高,并且可以毫不延遲地接收相關通知。
2、發布消息
創建主題后,發布方應用程序可以使用Publish方法將相關消息發布到該主題。為此,首先通過指定主題名稱來獲取主題的實例。NCache在發布消息時提供以下兩種傳遞模式:
- All(默認):將消息傳遞給所有注冊訂閱者。當需要廣播信息時,這很有用。
- Any:將消息傳遞給任何注冊訂閱者。
此外,為了有效地管理你的發布/訂閱緩存的存儲空間,你還可以設置消息的過期時間。
在以下代碼中,發布者將在現有主題newProducts上廣播有關新產品的消息。
//前提條件:緩存已連接
//主題“newProducts”已創建
string topicName = "newProducts"
//獲取主題
ITopic productTopic = cache.MessagingService.GetTopic(topicName);
//創建要在消息中發送的對象
Product product = FetchProductFromDB(10248);
//創建相應于對象順序的新消息
3、訂閱主題消息
創建主題后,訂閱者應用程序可以通過獲得訂閱來接收發布到該主題的消息。由于支持不同類型的訂閱,因此對非持久訂閱感興趣的訂閱者可以使用CreateSubscription方法;對于持久訂閱,則可以使用CreateDurableSubscription方法。
下面的代碼顯示訂閱者應用程序如何為主題newProducts創建訂閱。MessageReceived注冊回調以在收到通知時執行任何預期操作。例如,訂閱者可以在收到銷售通知時在MessageReceived回調中更新產品價格。
//前提條件:緩存已連接
//主題“newProducts”已創建
string topicName = "newProducts"
//獲取主題
ITopic productTopic = cache.MessagingService.GetTopic(topicName);
//創建并注冊主題newProducts的訂閱者
//指定回調函數MessageReceived
ITopicSubscription orderSubscriber = orderTopic.CreateSubscription(MessageReceived);
在上面的示例中,創建了一個非持久訂閱。此外,當需要在重新連接時從訂閱的主題接收舊消息時,訂閱者可以創建持久訂閱。
NCache還提供了一種基于模式的訂閱方法,其中NCache支持多個通配符來訂閱所提供模式下的單個/多個主題。
4、注冊通知
NCache使發布者能夠了解消息的狀態和主題的可用性。發布者應用程序可以注冊以下通知:
- MessageDeliveryFailure:如果消息因任何問題而無法傳遞,則通知發布者
- OnTopicDeleted:當消息被刪除時通知發布者
以下是發布者注冊這兩種通知的簡單方式:
//您有一個現有主題的實例productTopic
//注冊消息傳遞失敗
productTopic.MessageDeliveryFailure += OnFailureMessageReceived;
//注冊主題刪除通知
productTopic.OnTopicDeleted = TopicDeleted;
通過遵循上述步驟,可以將基本的發布/訂閱消息體系架構集成到任何一款ASP.NET或者.NET核心應用程序中。
總結
至此,總結一下NCache發布/訂閱模式為克服現有解決方案中存在的局限性提供了哪些好處。
- 由于具有線性可擴展性,NCache發布/訂閱可以通過添加緩存服務器和頻繁地執行負載平衡來處理越來越多的訂閱請求。該伸縮特征對用戶透明,而且不會妨礙通信過程。因此,您可以使用NCache發布/訂閱模式來輕松擴展通信性能。
- NCache發布/訂閱有助于持久訂閱、消息傳遞失效和傳遞失敗通知,以避免消息丟失。此外,NCache的分布式和復制體系架構確保了NCache的高可用性,以適應動態環境中訂閱者的連接。所有這些功能確保了可靠的通信。
- 由于NCache是內存中的分布式緩存,因此駐留在緩存中的消息存儲本身就很快。此外,NCache允許對駐留在緩存中的數據項指定是否過期,以便智能地管理存儲空間。
NCache的可擴展性、可靠性和存儲效率,以及發布/訂閱的松耦合和異步消息傳遞模式,使得NCache發布/訂閱功能在未來的.NET/NET核心應用程序分布式消息傳遞開發中極具前景。
原文鏈接:https://dzone.com/articles/pubsub-design-pattern-in-net-distributed-cache
譯者介紹
朱先忠,51CTO社區編輯,51CTO專家博客、講師,濰坊一所高校計算機教師,自由編程界老兵一枚。早期專注各種微軟技術(編著成ASP.NET AJX、Cocos 2d-X相關三本技術圖書),近十多年投身于開源世界(熟悉流行全棧Web開發技術),了解基于OneNet/AliOS+Arduino/ESP32/樹莓派等物聯網開發技術與Scala+Hadoop+Spark+Flink等大數據開發技術。