CQRS & Event Sourcing — 解決檢索應用程序狀態問題的一劑良方

如今,每一個開發人員都很熟悉MVC標準體系結構設計模式。大多數的應用程序都是基於這種體系結構進行建立的。它容許咱們建立可擴展的大型企業應用程序,但近期咱們還聽到了另外的一些有關於CQRS/ES的相關信息。這些方法應該被放在MVC中一塊兒使用嗎?他們能夠解決什麼問題?如今,讓咱們一塊兒來看看CQRS/ES是什麼,以及他們都有哪些優勢和缺點。html

CQRS — 模式介紹

CQRS(Command Query Responsibility Segregation)是一種簡單的設計模式。它衍生與CQS,即命令和查詢分離,CQS是由Bertrand Meyer所設計。按照這一設計概念,系統中的方法應該分爲兩種:改變狀態的命令和返回值的查詢。Greg young將引入了這個設計概念,並將其應用於對象或者組件當中,這就是今天所要將的CQRS。它背後的主要思想是應用程序更改對象或組件狀態(Command)應該與獲取對象或者組件信息(Query)分開。數據庫

下面,將通一張圖來講明應用程序中有關CQRS部分的組成結構:設計模式

![CQRS模式介紹](D:學習筆記譯文imgcqrs.jpg)

Commands(命令)—表示用戶的操做意圖。它們包含了與用戶將要對系統執行操做的全部必要信息。服務器

  • Command Bus(命令總線):是一種接收命令並將命令傳遞給命令處理程序的隊列。
  • Command Handler(命令處理程序):包含實際的業務邏輯,用於驗證和處理命令中接收到的數據。Command handler負責生成和傳播域事件(Event)到事件總線(Event Bus)。
  • Event Bus(事件總線):將事件發佈給訂閱特定事件類型的事件處理程序。若是存在連續的事件依賴,事件總線可使用異步或者同步的方式將事件發佈出去。
  • Event Handler(事件處理程序):負責處理特定類型的事件。它們的職責是將應用程序的最新狀態保存到讀庫中,並執行終端的相關操做,如發送電子郵件,存儲文件等。

Query(查詢):表示用戶實際可用的應用程序狀態。獲取UI的數據應該經過這些對象完成。架構

下面咱們將介紹有關CQRS的諸多優勢,它們是:app

  • 咱們能夠給處理業務邏輯部分和處理查詢部分的開發人員分別分配任務,但須要當心的是,這種模式可能會破壞信息的完整性。
  • 經過在多個不一樣的服務器上擴展Commands和Query,咱們能夠進一步提高應用程序的讀/寫性能。
  • 使用兩個不一樣的數據庫(讀庫/寫庫)進行同步,能夠實現自動備份,無需額外的干預工做。
  • 讀取數據時不會涉及到寫庫的操做,所以在使用事件源是讀數據操做會更快。
  • 咱們能夠直接爲視圖層構建數據,而無需考慮域邏輯,這能夠簡化視圖層的工做並提升性能。

儘管使用CQRS模式具備上述諸多的優勢,可是在使用前還須要慎重考慮。對於只具備簡單域的簡單項目,其UI模型與域模型緊密聯繫的,使用CQRS反而會增長項目的複雜度和冗餘度,這無疑是過分的設計項目。此外,對於數據量較少或者性能要求較低的項目實施CQRS模式不會帶來顯著的性能提高。框架

Event Sourcing — 案例研究

有這樣一個案例,咱們想要檢索任何一個域對象的歷史狀態數據,並且在任什麼時候間均可以生成統計數據。咱們想要檢查上個月、上個季度或者過去任什麼時候間的狀態彙總。想要解決這個問題並不容易。咱們能夠在特定的時間範圍內將額外的數據保存在數據庫中,但這種方法也存在一些缺點。咱們不知道範圍應該是什麼樣子,以及將來統計數據須要哪些數據項。爲了不這些問題,咱們能夠天天爲全部聚合建立快照,但它們一樣會產生大量的冗餘數據。異步

Event Sourcing(ES)彷佛是目前解決這些問題的最佳方案。Event Sourcing容許咱們將Aggregate(聚合)狀態的每個更改事件保存在Event Store的事件存儲庫中。經過Command Handler將事件寫入到事件存儲庫中,並處理相關的邏輯。要建立Aggregate(聚合)對象的當前狀態,咱們須要運行建立預期域對象的全部事件並對其執行全部的更改。下面咱們將經過一張圖來講明這一架構設計方式:性能

![event-sourcing](D:學習筆記譯文imgevent-sourcing.jpg)

下面咱們將列舉一些使用ES的優勢:學習

  • 時間穿梭機:能夠及時重建特定聚合的狀態。每一個事件都包含一個時間戳。根據這些時間戳能夠在特定的時間內運行事件或者中止事件。
  • 自動審計:咱們不須要額外的工做就能夠檢查出在特定的時間範圍內誰作了什麼以及改變了什麼。這和能夠顯示更改歷史記錄的系統日誌不一樣,事件能夠告知咱們每次更改背後所對應的操做意圖。
  • 易於引入糾正措施:當數據庫中的數據發生錯誤時,咱們能夠將應用程序的狀態回退到特定的時間點上,並重建當時的應用程序狀態。
  • 易於調試:若是應用程序出現問題,咱們能夠將特定事件內的全部事件取出,並逐條的重建應用狀態,以檢查應用程序可能出現問題的地方。這樣咱們能夠更快的找到問題,縮短調試所需的時間。

Aggregates

Aggregate(聚合)一詞在本文中屢次被說起,那它究竟是什麼意思?Aggregate(聚合)來自於領域驅動設計(DDD)的一個概念,它指的是始終保持一致狀態的實體或者相關實體組。咱們能夠簡單的理解爲接收和處理Command(包含Command Handler)的一個邊界,而後根據當前狀態生成事件。在一般狀況下,Aggregate root(聚合根)由一個域對象構成,但它能夠由多個對象組成。咱們還須要注意整個應用程序能夠包含多個Aggregate(聚合),而且全部事件都存儲在同一個存儲庫中。

總結

CQRS/ES能夠做爲特定問題的解決方案。它能夠在標準N層架構設計的應用程序的某些層中進行引入,它能夠解決非標準問題,常規架構中咱們所拿到的是最終狀態,在不少狀況下,當然當前狀態很重要,但咱們還須要知道當前狀態是如何產生的。CQRS和ES兩種概念應該一塊兒使用嗎?事實代表,並無。咱們想要統計任什麼時候間範文內的域對象狀態,而寫庫只能存儲當前狀態。引入CQRS並沒能幫助咱們解決這一問題。在下一章節中,咱們將引入Axon框架,Axon框架時間了CQRS/ES,用於解決某些域對象的一些特定問題,尤爲是收集歷史統計數據。咱們將闡述如何使用Axon框架實現CQRS/ES並實現與Spring Boot應用程的整合。

做者:LukaszKucik ,譯:譚朝紅,原文: CQRS and Event Sourcing as an antidote for problems with retrieving application states,譯文: (譯)CQRS & EVENT SOURCING — 解決檢索應用程序狀態問題的一劑良方
相關文章
相關標籤/搜索