一種簡單的CQRS架構設計及其實現

1、爲何要實踐領域驅動?html

近一年時間我一直在思考一個問題:「如何設計一個鬆耦合、高伸縮性、易於維護的架構?」。之因此有這樣的想法是由於我接觸的很多項目都是以數據庫腳原本實現業務邏輯。在項目初期使用這樣的方式野蠻開發彷佛顯得很高效,可是你們其實都清楚,正是這樣的項目讓你們拖入了加班的深淵。這種系統維護性差,沒法擴展,沒法編寫有效的單元測試,質量基本沒有保證。git

一個符合我心理預期的架構,必定不是靠使用某個代碼生成工具來完成的,這樣的項目把碼農培養成了徹頭徹尾沒有思想的個體。一個有追求的碼農,請遠離只會讓你使用代碼生成工具的「架構師」。sql

既然數據庫驅動的開發方式存在一些致命的問題,咱們很天然的想到了領域驅動開發(DDD)。在《我眼中的領域驅動開發》一文中,我提到了領域驅動設計不一樣於傳統軟件開發的一些思考方式。這些思想看起來很簡單,可是真正實踐起,思惟的轉變仍是有必定的難度。數據庫

在我職業生涯裏遇到的每個同事,在討論問題時都可以表現出本身擅長的一面,有的人思路比較清晰,有的人想法比較特別,跟這些人在一塊兒討論方案每每都會夠給你靈感。領域驅動開發這種方式須要融入有生命力的想法,每個人均可以參與到設計當中,軟件開發纔會變成一件有意思的事情。架構

2、使用EF來實踐領域驅動框架

我曾嘗試使用單純的EF來實踐領域驅動開發,老實說,我無法實踐成功。我想忘掉數據庫,可是很難。爲何這樣說?咱們知道領域驅動講求以領域模型爲基本單位思考問題,好比一次購物過程多是一個領域模型,我拋開了數據庫,創建的模型。這時來了一個需求,一個界面須要可以查詢一個範圍內的購物記錄,可能還有一些複雜的條件,這時候個人領域模型並不能很好的支持這樣的查詢,由於我在這以前壓根沒有考慮表結構如何設計,個人領域模型不是爲查詢設計的,因此這樣的一個查詢很容易存在性能問題。因此忘掉數據庫這一命題很難實現。異步

3、爲何會存在這樣的問題?分佈式

發生了這樣的問題我就在思考究竟是哪裏出了問題,是領域驅動開發這種軟件開發方式存在問題嗎?工具

形成這種局面的根本緣由在於「咱們給Domain強加了查詢的職責,長久以來的軟件開發模式太過於依賴於關係數據庫」,關係數據庫的首要任務是持久化數據,查詢只是他的部分能力,長久以來咱們即想讓關係數據庫存儲海量數據,又想讓查詢變得更高效。顯然,咱們對關係型數據庫的要求有點過度了。性能

我想這也是Greg Young提出了CQRS架構的緣由,當咱們在領域模型中去掉搜索和查詢的職責後,問題引刃而解。

4、實現CQRS有哪些難點?

既然CQRS纔是實踐DDD的最佳途徑,那麼咱們就可使用CQRS了麼?提到CQRS,不得不提到博客園的兩位CQRS元老級人物,dax.netnetfocus,他們兩位都貢獻了本身的CQRS框架,可是我猜想,即使是他們兩位大神也不會輕易在真實場景下使用CQRS架構。在我看來要真正實踐CQRS須要天時、地利、人和三者具有。

一、經典的CQRS是經過Event Sourcing來實現領域模型的還原和Query端的同步,這就要求領域模型的設計必定要一次到位,一旦Event被持久化到生產環境,這時候再修改設計就會帶來極大的難度。

二、對開發人員要求很是之高、要創建這樣的一直團隊須要長時間的磨合和培養。

三、採用CQRS的DDD因爲對設計要求較高,因此在開發初期並不能很快看到效果,這就要求公司可以容忍、理解而且支持,這條彷佛是最難符合條件的。

5、實現一個簡單的CQRS方案

通過分析,要想成功實踐領域驅動,查詢與命令職責必定要分離,咱們仍是要實現CQRS,可是再也不經過Event Sourcing來實現,從而減小複雜度。下面就是個人一個不太成熟的想法:

一、Domain經過EF持久化。

二、每一個Domain邏輯在實現中都將產生兩種固定類型的Event,***CreatedEvent和***UpdatedEvent。

三、因爲取消了Event Sourcing,因此下降了Domain設計的複雜度,此時的關係型數據就至關於最新的快照。

四、在EF的UnitOfWork執行成功後註冊發佈事件的回調,確保領域模型持久化成功才發佈事件。

五、事件發佈到雙工ServiceBus中,雙工ServiceBus包含一個InMemory的同步ServiceBus和一個支持消息隊列的異步ServiceBus。

六、領域發佈事件後,先有InMemory的同步ServiceBus更新由Redis實現的QueryModel,確保界面會同步刷新,單個Domain的讀取將經過Redis來實現。緊接着消息會發送到支持消息隊列的異步ServiceBus。

七、消息進入消息隊列後供其餘子系統消費,同時更新Elastic Search,界面的複雜搜索將經過Elastic Search來實現。

八、此時的系統已經演化爲一個鬆耦合、可擴展、基於領域模型的分佈式架構方案。

當查詢和讀取Domain的職責被分攤到Elastic Search和Redis後,這時候再設計領域模型就不會有外界因素來干擾你。

另外整個系統不會出現一句sql,讓sql這種反人類的語言去見鬼吧,此時要是還有誰要是以爲「必須得寫sql,sql效率高」。你過來,我保證不打死你。o(^▽^)o

目前的Demo基於以上的想法正在一步步實現中,請關注。另外,因爲水平有限,整個架構設計不免有不合理的地方,歡迎提出寶貴意見。

https://git.oschina.net/richieyangs/BookLibrary

相關文章
相關標籤/搜索