前言
ENode是一個應用開發框架,爲開發人員提供了一整套基於DDD+CQRS+ES+EDA架構風格的解決方案。ENode從發佈1.0開始到如今的差很少兩年時間,我幾乎每週都在更新設計或實現代碼。以致於歷來沒有一個穩定的版本能夠提供給你們,很是慚愧。但我相信,隨着時間的推移和個人努力的積累,ENode必定會愈來愈穩定和成熟的。我以爲我此刻很幸福,由於我有本身的興趣且有機會在業餘時間爲了本身的興趣而奮鬥。node
ENode開源地址:https://github.com/tangxuehua/enodegit
今天是個開心的日子,由於我終於使用ENode開發出了一個比較有說服力的真實案例,一個在線會議位置管理與訂購系統。該案例與微軟的Microfost CQRS Journey案例的功能一致,只是是用ENode開發完成的。目的是爲了展現:github
- 如何使用ENode支持DDD領域層的實現;
- 如何使用ENode實現CQRS+ES的架構;
- 如何使用ENode實現事件驅動的架構(EDA);
另外,在案例開發過程當中,也不斷髮現了ENode, EQueue的不少問題。因此,經過作這個案例,也幫助ENode, EQueue完善了不少。真是要實踐才能進步啊!服務器
ENode架構簡介
ENode目前的架構已經和最初的1.0版本有較大的差異了。好比,沒有了對Redis的依賴,增長了Command Store的設計。最新版本的ENode架構圖以下:架構
熟悉CQRS架構的人應該對這個圖不太陌生。須要強調的有兩點:併發
- 新版的架構圖中,Domain Aggregate是常駐內存的;聚合根的職責就是封裝狀態、業務規則,同時產生領域事件;
- 新增了一個Command Store,用於實現Command的冪等處理;
關於圖中的其餘部分的介紹,請參看我以前寫的關於ENode系列的文章。 app
ENode關鍵特性
- 實現了CQRS架構,支持分佈式,基於隊列的水平擴展,框架設計之初就考慮了架構的各個節點的水平擴展;
-
面向高併發設計;架構層面,充分考慮到了如何解決併發問題;經過用EQueue實現服務器之間的消息路由、經過單機內部實現相似Actor Mailbox的設計,從而避免併發的產生。提升CQRS架構C端的總體寫入吞吐量;即使在某些極端狀況下出現併發問題,也支持自動的樂觀檢測,並自動重試;另外,架構層面,規定一個command只能涉及一個聚合根的修改,從而規範應用開發者必須嚴格按照消息驅動的思路來實現複雜的業務流程,而不能使用工做單元的方式,以事務的方式實現數據的強一致性;框架
- 嚴謹的消息冪等處理支持;因爲ENode是消息驅動的架構,因此對消息的冪等性處理,是框架關注的一個重要的方面,並在架構層面作了支持。這使得應用開發人員沒必要擔憂消息的重複處理帶來的問題。
- Domain Aggregate常駐內存;這個設計能夠提升C端command的處理性能。由於咱們沒必要像傳統的方式那樣先把聚合根從db取出來,再修改,再保存回去了;
- 框架爲開發人員展現瞭如何更好的實現Sagas,在CQRS架構中,Sagas指基於消息驅動的業務流程;一個Saga包含若干個聚合根以及一個(一般)流程管理器(Process Manager);聚合根維護流程中的全部參與者對象的狀態以及流程自己的狀態,流程管理器負責定義和實現流程控制邏輯,無狀態;流程管理器的實現是經過響應事件、異常、應用層消息,而後發送相應的命令,從而實現消息驅動的流程;
- 採用Event Sourcing(簡稱ES)的方式來持久化聚合根狀態;經過ES實現聚合根狀態的還原以及通用的併發控制,經過聚合根ID+事件版本號做爲惟一索引的思路實現樂觀併發控制;
- 消息除了command, domain event外,還支持exception message, application message;這兩種消息是咱們在遇到有些消息不適合用domain event來表達時須要使用到;好比聚合裏有時咱們要修改某個狀態前會先作業務規則的檢查判斷,若是不合法,一般會拋異常,而後這個異常咱們又但願可讓流程管理器知道,從而流程管理器能夠作後面的回滾或補償措施;另外,咱們有時可能會在應用層面(command handler裏)和其餘外部系統發生交互,那交互的結果,使用應用層的消息更合理;ENode在架構層面,對上面這些消息作了統一的支持;
- 框架提供返回單個command執行結果以及阻塞等待command執行結果的支持,這個對於開發者但願同步執行command並知道command執行結果的時候,很是有幫助;這樣開發者就不用本身去輪訓了。
- 除了對消息的冪等處理的支持外,ENode對domain event的順序處理,也作了充分的考慮和支持,確保當C端產生的domain event同步到Q端時,Q端處理時,框架層面能確保Q端的處理順序不會亂序。從而保證C,Q兩端的數據是最終一致的;
- 保證消息能至少被處理一次;主要思路是確保消息的:1)持久化;2)消息ACK後才認爲已消費;
- 支持一個聚合根一次能夠產生多個domain event;雖然大部分狀況,一個聚合根一次只會產生一個domain event,但有些場景,可能會產生兩個或多個。此時,這些事件會以一個事件流的方式一塊兒apply到當前聚合根;同時,在Q端,框架也會經過必要的手段,與用戶代碼一塊兒保證了事件流中的事件的處理順序的正確性;
- ENode所使用的分佈式消息隊列EQueue,參考了阿里的RocketMQ的架構思想,具備高性能、可擴展、輕量級的特性,支持不受限於機器內存大小的消息堆積能力,並且是純C#開發。同時還提供了簡單實用的管理控制檯,可讓咱們輕鬆的管理消息隊列。好比能夠方便的動態增長、禁用、啓用、刪除隊列,查詢消息內容、消息消費進度,等信息;目前,EQueue也已經通過多個迭代,而且已經有真實用戶進行使用,功能基本趨於成熟穩定。
Conference案例簡介
Conference是一個微軟開發的,基於DDD+CQRS+ES的一個開源項目。項目主頁:cqrsjourney.github.iodom
這個項目,對咱們你們學習DDD領域驅動設計、CQRS+ES的架構,很是有幫助。分佈式
- 該案例從業務上,實現了一個典型的電子商務系統的關鍵環節:商品管理、庫存管理、下單、減庫存、支付;
- 該案例從技術上,很好的展現了CQRS架構的優勢。好比能夠在Q端定製不一樣的視圖,以應對不一樣的查詢需求;
- 該案例很好的向咱們展現瞭如何劃分領域,劃分邊界上下文(bounded context),並如何使用不一樣的架構技術,實現不一樣的上下文,很是具備學習價值。
正是由於這個項目的以上優勢,讓我有興趣使用ENode做爲技術支撐,實現一樣功能的系統。在重寫的過程當中,保留了全部非技術的東西,好比邊界上下文的劃分、領域層等;全部技術相關的部分,用ENode替代。
使用ENode實現的Conference開源項目地址:https://github.com/tangxuehua/conference
演示地址,後臺:http://www.enode.me/conference,前臺:http://www.enode.me/registration
但願有興趣的同窗,能夠去下載源代碼進行研究。瞭解ENode,最快的方法就是從案例代碼開始。若是想進行交流,能夠加QQ羣:185916873,隨時歡迎有興趣的道友加入。
最後,貼一個Conference案例中訂單處理的Sagas流程圖:
不早了,實在寫不下去了,就到這吧。