ENode框架Conference案例分析系列之 - 架構設計

Conference架構概述

先貼一下Conference案例的在線地址,UI由於徹底拿了微軟的實現,因此都是英文的,之後我有空再改成中文的。html

前一篇文章介紹了Conference案例的上下文劃分和領域模型的設計思路,本文想介紹一下Conference案例的架構設計。我作Conference案例的出發點是爲了給你們展現如何使用ENode框架來開發DDD+CQRS+ES+EDA風格的應用程序。因此,Conference案例的架構天然就是使用這個架構了。下面我展開來講一下:node

  • DDD:是軟件設計的一種方式,出發點是經過領域模型封裝業務邏輯和業務規則,解決領域內的複雜業務問題;
  • CQRS+ES:命令查詢分離的架構,經過將命令查詢分離,作處處理業務邏輯的部分和查詢的部分能夠分離,方便兩部分能夠各自發展,不受對方約束;CQRS的實現方式主要有兩種:1)共享存儲的CQRS,即背後的數據庫存儲是一份,數據是一份,只是在代碼、架構層面作到命令和查詢邏輯的分離。這種方式很好的利用了CQRS的思想,同時也不會有數據一致性的問題,由於是共享存儲的,因此CQ兩端不須要有消息通訊,大部分應用程序用這種方式便可。2)存儲分離的CQRS,這種方式主要用ES(Event Sourcing,事件溯源)技術來完全實現CQ兩端的徹底分離,這種架構比較複雜。C端不存儲對象的最新狀態,而是存儲對象產生的全部事件;讓咱們要還原一個對象時,經過ES的方式來還原。而後Q端經過訂閱C端產生的事件來更新讀庫。這種架構是一種EDA的架構,CQ兩端須要經過事件來進行聯繫,因此是一種面向最終一致性思路的架構。那這種方式有何好處呢?它和前面我說的第一種方式的CQRS架構,我以爲主要的好處是,咱們能夠設計一套框架,幫咱們從架構層面解決併發問題、消息的冪等處理問題;同時結合in-memory, group commit等技術,還能大大提升系統的吞吐量以及抵禦高峯的能力(由於消息能夠堆積);從而可讓開發人員不用關心技術問題,專心實現業務邏輯和設計業務流程便可。而共享存儲的CQRS架構,是須要咱們每次Command修改完聚合根以後,須要主動保存(可能經過ORM實現)聚合根的狀態的。總之兩種實現方式各有優缺點,關於CQRS架構的更多介紹,我博客裏已經寫過不少文章了,有興趣的朋友能夠進一步看看。
  • EDA:這是一種事件驅動的架構,他和SOA架構屬於同一個層次;EDA是事件驅動的思想,即B訂閱A產生的消息來進行主動響應的思路;而SOA是一種面向服務而後經過服務之間相互調用(RPC)的思想;這是兩種不一樣的架構風格,咱們在不一樣的場景會使用不一樣的方式。ENode實現的是EDA架構,面向的是最終一致性。ENode在不少方面都體現出了EDA的思想。好比:
    1. ENode規定,一個Command不能同時修改兩個聚合根,必須經過事件驅動的方式,先修改一個聚合根,而後該聚合根產生事件,而後另外一個聚合根訂閱響應事件,再修改本身的狀態,從而實現兩個聚合根之間的交互。這個思路 背後的原則是:聚合內強一致性、聚合之間最終一致性。
    2. CQRS兩端,也是最終一致性,經過事件來同步數據。C端產生的事件經過MQ被Q端訂閱,而後Q端更新本身的讀庫,從而實現數據的最終一致性;
    3. 兩個BC(Bounded Context,上下文)之間的數據傳遞,也是基於消息驅動的思想。好比支付上下文在完成支付後,會產生一個消息,而後訂單上下文訂閱響應該消息,實現上下文之間的交互。

ENode架構圖

也許有人沒看過ENode架構圖,呵呵。我這裏再貼一下,誰若是要進一步瞭解ENode的架構設計,能夠看我博客中的其餘關於ENode框架的介紹文章。git

Conference項目結構介紹

 

 

 

前篇文章中咱們瞭解到,Conference案例共有三個上下文,分別是:會議管理(ConferenceManagement)、訂單處理(Registration)、訂單支付(Payment)。關於這個案例,微軟的實現和個人實現有所不一樣,但上下文的劃分是一致的。微軟的實現中,三個上下文用的技術架構是不一樣的。github

  • ConferenceManagement,因爲只是後臺管理系統,業務邏輯相對不是很複雜,因此,採用的是普通的三層結構;
  • Registration,因爲是整個系統的整個Conference系統的核心,業務邏輯和流程都比較負責,因此使用的是CQRS+ES的架構;
  • Payment,因爲Conference這個項目只是一個案例,因此其實沒有真正實現支付的功能,只是簡單示範了一下功能,因此這個上下文的業務邏輯也不太複雜。可是因爲訪問量也比較大,每一個訂單都會須要支付,因此也是採用的CQRS的架構,可是由於業務邏輯不復雜(不須要在存儲層面也分離),因此沒有采用ES技術。Payment聚合根裏產生事件,最後Repository保存聚合根的最新狀態,而後經過事件總線發佈事件,通知Registration上下文訂單支付結果。

上面我簡要分析了一下微軟的實現。我以爲微軟的實現仍是很是有參考價值的,由於它充分展現了DDD中不一樣的BC能夠採用不一樣的技術架構實現,而後經過EDA的總體架構,來實現3個BC之間的數據交互。很是棒。數據庫

下面我說一下ENode實現的Conference案例。微信

前面說過,本案例主要是爲了展現ENode框架的使用,因此我給這3個BC都是使用ENode框架實現,因此每一個BC都是採用的DDD+CQRS+ES的技術架構。因爲有ENode框架的支持,因此代碼實現還不算複雜,可讓開發只須要專一於業務邏輯的實現便可,不須要關心消息傳遞,消息不丟失,消息冪等處理,併發問題,C端數據持久化等技術問題。這些技術問題若是沒有框架支持,要由應用開發人員本身實現,是頗有難度的。經過這個案例實踐下來,基本能夠證實ENode框架是能夠被使用來開發出一個可實際使用的項目的,這點我目前頗有信心。架構

採用ENode框架開發一個BC的實現的時候,咱們通常須要定義如下的一些工程: 併發

  • Commands,定義全部的命令;
  • CommandHandlers,定義全部的CommandHandlers;
  • Domain,就是對應DDD領域層;
  • ReadModel,表示CQRS的Query Side的實現,主要包括query service的實現,以及event handler用戶更新讀庫;
  • Messages,定義了當前BC全部對外的消息,其餘BC能夠訂閱這些消息;消息都是DTO。
  • MessagePublishers,該項目的職責是訂閱當前BC內部的Domain Event,而後轉換爲Message,而後把Message發佈出去,從而實現通知到其餘的BC。之因此要定義出Message這種DTO,是由於,我認爲DDD中的Domain Event最好不要跨BC,由於Domain Event是屬於當前Domain的東西,Domain Event中可能會包括當前Domain裏定義的各類值對象;若是直接發佈到其餘BC,就會致使BC的邊界不清。
  • Repositories,這種工程的做用就是實現Domain裏可能定義的倉儲接口。爲什麼使用ENode框架後,還須要定義倉儲接口?由於有些狀況下,咱們須要有一些二級索引的檢查,好比建立會議時,咱們要判斷會議的某個屬性是惟一的,可是ES不支持二級索引,而咱們又不能經過查詢讀庫來判斷惟一性。因此咱們須要在C端設計一些存儲聚合根索引信息的倉儲,用來支持二級索引。左邊的圖裏我把項目名稱命名爲Repositories.Dapper,說明這個倉儲是用Dapper來實現的。若是咱們用EF來實現,那能夠命名爲Repositories.EF。
  • ProcessManagers,這種項目是用來承載CQRS架構中的Saga的,即流程管理器。Saga的做用是對業務流程進行建模。Saga的原理也是事件驅動,一個Saga會響應事件,而後發送命令。經過事件+命令串聯的方式實現事件驅動架構的業務流程。Saga(ProcessManager)是無狀態的,全部的狀態應該都在聚合根裏。這點我和微軟的Saga的設計也是不一樣的,有興趣的朋友能夠看一下微軟的實現。

另外,上面介紹了單個BC內部可能出現的項目,這些項目是我經過作這個案例後總結出來的以爲能夠給開發者作參考的相互劃分方式。你們若是以爲這樣的方式很差,能夠本身決定如何劃分。經過上面的劃分,咱們的頂層Web項目只須要依賴簡單的Commands,ReadModel這兩個項目,就能夠實現命令的發送和讀庫數據的查詢了。而BC之間的交互,另外一個BC只須要依賴當前BC的Messages項目就行,作到了最小的依賴。app

最後介紹一下剩餘的幾個頂層項目:框架

Conference案例有兩個Web項目,分別爲用戶提供Conference的後臺管理和前臺訂單預約的Web界面。這個不須要多解釋了應該。而後,還有3個ProcessorHost項目。這3個項目分別是3個BC負責處理後臺業務邏輯的頂層宿主項目。它們只須要用控制檯應用或者Windows服務的方式啓動便可(案例裏的實現同時支持這兩種方式的啓動,會自動識別當前的應用程序類型)。這3個後臺服務,它們都是從EQueue訂閱消息,而後處理消息的方式,實現本身的功能。因此它們的惟一數據來源就是EQueue。那EQueue消息隊列的服務端是哪一個呢?就是最下面的MessageBroker,這個項目承載了整個系統的消息中心,也就是EQueue的Broker。全部的消息都會發送給MessageBroker,而後相關的ProcessorHost訂閱相關的Topic,實現消息的消費。

結尾

下一篇文章打算從代碼的角度,以建立一個會議爲例,從前臺Controller到最後更新讀庫的整個代碼鏈路簡單介紹一下,方便讀者能對實現某個功能要寫哪些代碼先有一個清晰整體的認識。

10
0
« 上一篇: Async All the Way
» 下一篇: ENode框架使用場景簡述
相關文章
相關標籤/搜索