DDD 中的 CQRS(命令查詢職責分離)架構模型有哪些?

命令 / 查詢分離 (CQS)

1988 年,Bertrand Meyer 在面向對象的軟件設計一書中設計了 CQS 原則。簡單來說,這個原則是說程序應當要麼修改系統(Command),要麼返回查詢結果 (Query),軟件中應當保持命令與查詢的分離。

儘管 Martin Fowler 在他 2005 年的博客文章中也提到,這種分離並非總是可能的,一個很好的例子是返回一個剛插入的記錄的 id。首先,你要把記錄持久化(Command),其次,你要獲得它新分配的 id(Query)。

CQRS 架構

CQRS 建議將應用程序層分爲兩個方面,即命令端(Command)和查詢端(Query)。

查詢端負責優化讀取數據。從持久化獲取數據,然後將它們映射到展現層表單,這些表單通常被標識爲數據傳輸對象(DTO)。

命令端關注優化寫入數據。命令執行各種用例,修改實體狀態並將其持久化。

通過分離讀寫操作,我們提高了性能,並在系統中支持關注點分離原則。

本文介紹 3 種主要的 CQRS 架構實現。

一、單數據庫 CQRS

單一數據庫 CQRS 模式沒有正式名稱,Mattew Renze 在他的課程 Clean Architecture 中將其命名爲單一數據庫 CQRS,我也選擇這個命名。

單數據庫 CQRS

顧名思義,雙方都在和一個數據庫對話。Command 在域中執行用例,從而修改實體的狀態,然後通過 ORM 如 Entity Framework Core 或 Hibernate 將實體保存到數據庫中。

Query 直接通過數據訪問層執行,數據訪問層要麼是使用各種 ORM,要麼通過存儲過程。

二、雙數據庫 CQRS

在 “雙數據庫” 方式中,我們需要兩個數據庫,一個用於寫操作,一個用於讀操作。命令端使用針對寫操作優化的數據庫。查詢端使用針對讀取操作優化的數據庫。

雙數據庫 CQRS

命令每改變一個狀態,修改後的數據就必須從寫數據庫推送到讀數據庫中,或者作爲一個跨兩個數據庫的分佈式事務,或者使用最終一致性模型。

這種架構給軟件的查詢端帶來了數量級的性能提升,這是有利的,因爲一般系統在讀數據上花費的時間一般比寫數據要更多。

三、事件源 (Event source) CQRS

最後一種是最複雜的 CQRS 架構。與前面兩種方式相比,事件源存儲數據的思路完全不同。

在事件源方法中,我們並不只存儲實體的當前狀態,而且將實體發生的每一個狀態作爲快照來存儲。實體並不是以標準化數據的形式保存,而是通過事件的時間戳來保存它們的變更。

事件源 CQRS

事件源帶有以下好處:

但在另一方面,這種方式實現很複雜,如果你不能從其中受益,那麼用這個模式可能適得其反。

小結

CQRS 真正的威力在於可以對寫和讀操作進行不同的優化。但在另一方面,系統會變得更加複雜,命令端和查詢端代碼不完全一致。並且由於存在多個數據庫,管理更復雜,需要更繁瑣的 ORM 映射。

文中鏈接:

  1. clean architecture https://www.pluralsight.com/courses/clean-architecture-patterns-practices-principles

  2. Command-query separation https://en.wikipedia.org/wiki/Command%E2%80%93query_separation

  3. Martin Fowler’s 談 CQS https://martinfowler.com/bliki/CommandQuerySeparation.html

  4. 分離點關注 1 https://en.wikipedia.org/wiki/Separation_of_concerns

  5. 分離點關注 2 https://www.goodreads.com/quotes/tag/separation-of-concerns

  6. 最終一致性 https://theacetechnologist.com/post/eventually-consistent-architecture-pattern/

英文原文:

https://levelup.gitconnected.com/3-cqrs-architectures-that-every-software-architect-should-know-a7f69aae8b6c

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/V2HCrEqFhdd4mTr58z3gqw