分散式系統的訊息&服務模式簡單總結
在一個分散式系統中,有各種訊息的處理,有各種服務模式,有同步非同步,有高併發問題甚至應對高併發問題的Actor程式設計模型,本文嘗試對這些問題做一個簡單思考和總結。
一、訊息的“推、拉模式”
在傳統的Client/Server結構中,資訊獲取方式是按“拉”(Pull)的模型進行的:伺服器根據使用者終端傳送的服務請求進行處理並返回使用者所需的結果。在Push系統中,伺服器把資訊“推”給使用者終端系統。雖然兩者資料傳輸的方向都是從伺服器流向使用者,但操作的發起者是不同的。從“信源”與“使用者”的關係來看,資訊的流動可分為兩種模式,即資訊推送與資訊拉取模式。
在成熟的訊息佇列產品中,對訊息的獲取,也分為訊息拉取模式和訊息推送模式,這兩種模式各有優點,需要根據應用的特點來選擇。
Push“推”的好處包括:
1、高效。如果沒有更新發生,不會有任何更新訊息推送的動作,即每次訊息推送都發生在確確實實的更新事件之後,都是有意義的。
2、實時。事件發生後的第一時間即可觸發通知操作。
3、可以由釋出者確立通知的時間,可以避開一些繁忙時間。
4、可以表達出不同事件發生的先後順序。
Pull“拉”的好處包括:
1、如果觀察者眾多,訂閱者來維護訂閱者的列表,可能困難,或者臃腫,把訂閱關係解脫到觀察者去完成。
2、觀察者可以不理會它不關心的變更事件,只需要去獲取自己感興趣的事件即可。
3、觀察者可以自行決定獲取更新事件的時間。
4、拉的形式可以讓訂閱者更好地控制各個觀察者每次查詢更新的訪問許可權。
二、同步、非同步和並行
一個大型的程式系統常常是由很多不能功能模組組成的。程式系統執行時不同功能模組要按一定順序執行,以協同完成一件任務。功能模組協作執行完成一件任務存在同步和非同步兩種方式。
如果在某一時間段,這個程式系統的所有功能模組都在為完成相同的一件任務而服務,某一個功能模組在完成一件任務的子任務後,需要等待其他功能模組完成子任務,這樣只有當全部功能模組按順序完成一件任務後,程式系統才能接收下一個任務,功能模組是序列執行,這稱之為同步模式。
反之,在某一時間段,這個程式系統的不同功能模組可以獨立執行完成一件任務的子任務,無須等待其他功能模組完成子任務就可以繼續處理下一件任務的子任務,功能模組是並行執行,這稱之為非同步模式
反映在OLTP程式系統中,一個交易就是一個任務。如程式系統一次只完成一個交易,在這個交易沒有完成前,程式系統不接受其他交易,這就是同步模式。如程式系統把交易任務分拆成幾個獨立的子程序,每個子程序獨立完成交易的一個子任務,幾個子程序同時執行,這就是非同步模式。由於交易在模組之間是按照一定順序執行的,所以對一個具體交易而言,模組之間任務執行時並不表現為並行執行,但對大批量交易的巨集觀效果而言,模組之間卻是表現為並行執行。
三、服務的處理模式
訊息獲取的“推、拉模式”,實際上是站在訊息的消費者,也就是客戶端的角度來說的,即訊息是伺服器推送給我,還是我去拉取訊息的問題。如果站在伺服器的角度,也就是訊息的生產者來看,也有2種模式。
2.1,“請求-響應”模式
這是絕大部分Client/Server結構對資訊的處理模式,伺服器提供不間斷的服務,等待客戶端的請求。一旦接收到客戶端的請求,伺服器馬上處理該請求,然後生成處理結果,最後將結果響應給客戶端。請求-響應模式通常是一對一的響應,客戶端主動發起請求,服務端被動響應。典型的例子就是HTTP伺服器。
請求-響應模式要求伺服器能夠實時的進行響應,客戶端接收到響應後在進行下一步處理,因此它的處理過程常常是“同步”的。但有時候,客戶端發出的請求服務端需要進行長時間的處理才能返回結果給客戶端,讓客戶端長時間等待就不合理了,這時候可以使用非同步處理技術,客戶端發出請求後就返回到自己的處理執行緒,伺服器處理完成後回撥客戶端提供的方法。廣泛流行的Ajax 即“Asynchronous Javascript And XML”(非同步 JavaScript 和 XML),就是這種非同步處理請求-響應模式的方案,它提供了一種建立互動式網頁應用的網頁開發技術。
2.2,“釋出-訂閱”模式
有時候,不要求伺服器收到請求後立刻給客戶端響應結果,而是在隨後的某個時間,伺服器才能處理完成結果或者說生產訊息,通過某種方式送到客戶端。這種通訊模式特別像報刊的訂閱:出版社出版一份報刊,讀者訂閱此報刊,然後出版社通過郵局將報刊定期投遞到讀者手中。所以我們將這種通訊模式形象的稱呼為“釋出-訂閱”模式,即伺服器(釋出者)釋出一個訊息主題,客戶端(訂閱者)訂閱此主題,然後伺服器定期或者不定期的將訊息推送給客戶端。
由於“釋出-訂閱”模式訊息不能及時響應給客戶端的特點,所以通常實現為非同步處理模式,客戶端提供一個回掉函式,服務端有訊息的時候這個回掉函式被呼叫。
受限於Client/Server結構兩端所處的位置不同,客戶端可能在內網通過NAT方式上網,並且HTTP短連線的應用特點,Client/Server並不是實時連線的,伺服器無法主動連線客戶端,那麼訊息也就無法實時推送給客戶端,只有客戶端不斷的請求伺服器來獲取最新的訊息,於是出現了“長輪詢”(long-pull)技術,伺服器會Hold住客戶端的連線,如果在超時之前還沒有結果,那麼伺服器生成一個空訊息給客戶端;客戶端收到此空訊息後再次發起請求,知道收到伺服器真正的訊息為止。
但是,長輪詢需要消耗過多的伺服器資源和網路資源,並且瀏覽器的併發請求數通常也有限制,所以長輪詢並不是一個很好的方案,如果伺服器能夠主動將訊息推送給客戶端就可以避免這些問題,於是基於“長連線”的訊息推送技術產生了,WebSocket就是這樣一種技術:瀏覽器發起一個普通請求,告訴伺服器這是一個WebSocket請求,然後伺服器升級服務處理級別,切換到Socket處理方式,與客戶端瀏覽器建立Soket通訊通道,當伺服器有訊息後就推送給瀏覽器。
如果客戶端不是瀏覽器,可以直接和伺服器建立Socket通訊並保持為長連線,由伺服器推送訊息給客戶端。比如PDF.NET的訊息伺服器框架(MSF),就是基於WCF的TCP雙工長連線,來實現伺服器推送訊息的。
所以,“釋出-訂閱”是一種服務模式,它可以通過短連線的客戶端輪詢請求(pull)或者基於長連線的伺服器主動推送(push)來實現。訊息的“推、拉模式”,均可實現“釋出-訂閱”這種種服務模式。
四,訊息服務框架(MSF)的服務模式
訊息服務框架(MSF)支援前面講的兩種服務模式:“請求-響應”模式,“釋出-訂閱”模式。在MSF的具體實現中,“請求-響應”模式是“釋出-訂閱”模式的特例,內部都是通過後者的基礎實現的,可以這麼認為:“請求-響應”模式是一種及時響應的,一對一訊息推送的“釋出-訂閱”模式,也就是說,前者只有一個客戶端,或者有多個客戶端。MSF的這種處理模式,得到一個意外的結果:
同一個服務,既可以是“請求-響應”模式的,又可以是“釋出-訂閱”模式,具體取決於客戶端的呼叫方式。
有關MSF的兩種服務模式,請參考前篇:
《“一切都是訊息”--MSF(訊息服務框架)之【請求-響應】模式 》
《“一切都是訊息”--MSF(訊息服務框架)之【釋出-訂閱】模式》
兩種模式從主動性上來看,“請求-響應”模式是客戶端主動的,所以我將它簡稱為 “請求模式”,而“釋出-訂閱”模式是伺服器主動的,所以我將它簡稱為 “推送模式”。
MSF的“請求模式”也支援伺服器推送訊息,即在一次請求過程中,伺服器可以多次推送訊息給客戶端,“回撥”客戶端提供的函式,所以這種回撥結果通常作為伺服器最終響應結果的“中間結果”。比如請求一個檔案上傳服務,伺服器多次回撥客戶端,讀取客戶端的檔案資料。
MSF的“推送模式”分為定時推送模式和事件推送模式,事件推送模式的意思是將伺服器發生的事件作為訊息推送到客戶端,然後客戶端響應此事件型別的訊息,等同於客戶端訂閱了伺服器的事件,本質上就是一種“分散式事件”了。
五,Actor物件的啟用與生命週期
Actor程式設計模型是一種基於訊息處理的併發程式設計模型,它有幾個典型特點:
Actor之間只通過訊息進行通訊,沒有觀察者模式或者事件程式碼的耦合;
Actor的內部狀態只能由自己改變
Actor可以通過訊息啟用別的Actor以建立響應式的任務,這種型別的任務處理是易於並行處理的。
訊息服務框架(MSF)是基於分散式訊息處理的框架,在設計上它具有Actor模式的特點,MSF的每個服務物件例項都是一個Actor,MSF通過不同的服務模式來控制Actor的生命週期:
“請求-響應”模式:每次請求,伺服器會建立一個獨立的服務物件例項;
“釋出-訂閱”模式:每一個相同“主題”的訂閱,伺服器會建立同一個服務物件例項。
這裡說的“主題”,指的是相同的服務名,相同的方法名和相同的引數值,在MSF中,也稱呼為“訂閱任務”。客戶端訂閱不同的主題,服務端會建立不同的服務物件例項。
不管是哪種服務模式,MSF的服務物件例項(Actor)它的生命週期都會執行到服務方法執行完成,但是“釋出-訂閱”服務模式的服務物件例項,它執行完成任務後可以繼續等待直到設定的超時時間之後,這樣不必建立新的服務物件而接受下一次的訂閱請求。當然,也可以在服務的訂閱任務處理完成後,通過編碼及時停止服務而不等待。
建立同一個服務物件例項有一個很大的好處,它讓多個訂閱的客戶端共享了同一個服務物件例項,將會非常有用。
比如客戶端訂閱了產品A的服務,相當於客戶端激活了服務端的一個物件,這個物件將存活到它的任務處理完成為止。如果另外一個客戶端也訂閱了產品A的服務,新客戶端將一樣收到服務端推送過來的訊息。
假設客戶端A激活了服務端B服務,而服務端B服務又去呼叫服務端C服務,將啟用服務端C服務.....一個分散式物件服務的鏈式啟用過程開啟了。你只需要去呼叫需要的服務,服務的啟用和服務物件的銷燬,MSF框架會幫你搞定一切。
總之,MSF的這種服務之間的通訊都是通過訊息進行的,物件之間只有訊息,並且是分散式的訊息,所以,MSF是一個真正的分散式Actor程式設計模型。
原文地址:https://www.cnblogs.com/bluedoctor/p/8127122.html
.NET社群新聞,深度好文,歡迎訪問公眾號文章彙總 http://www.csharpkit.com