DDD-CQRS的落地案例


摘要

在之前的文章DDD-CQRS能解什么問題中,闡述了什么是CQRS。但是並沒有業務需求可以應用CQRS。最近需要處理一個文本增量更新的業務,經過需求分析后,嘗試使用CQRS來解這個問題

問題分析

一個文本頁面編輯,對象很大,之前是全量保存。涉及到的網絡傳輸對象比較大,經常超時OOM,所以交互改成,只保存修改的部分,也就是增量更新。

之前業務中沒法使用CQRS,在於使用CQRS后,數據的維護變得異常麻煩。比如我對一個表單進行了反復修改,生成了N份歷史修改數據,獲取最新數據時需要對這些歷史數據進行合並,變得異常麻煩。
這次業務能夠使用在於,

  1. 拆分寫,能夠有效的減少數據傳輸。
  2. 讀寫可以分離,分別擴展
  3. 通過事件溯源,可以恢復數據到任意編輯的版本

具體設計

系統整體采用CQRS+Event-Sourcing來實現

CQRS

CQRS模式通過使用不同的接口來分離讀取數據和更新數據的操作。CQRS模式可以最大化性能,擴展性以及安全性,
還會為系統的持續演化提供更多的彈性,防止Update命令在域模型Level發生沖突。

文本編輯這塊領域模型很薄,沒有什么領域校驗與約束,按讀取數據/更新數據分離,當讀寫壓力不同時,以后可以拆分成不同的服務,分別擴展。

Event Sourcing(事件溯源)

a.不保存對象的最新狀態,而是保存對象產生的所有事件
b.通過事件溯源(Event Sourcing,ES)得到對象最新狀態;

系統整體分為三大部分

一. command

所有數據修改命令,更新Command、撤銷Command、覆蓋Command
會持久化存儲到CommitRepository中。然后發出事件消息

二. event-handle

對於文本編輯這個case,事件處理主要是合並提交的command event。否則事件溯源時,需要處理的數據更新事件太多,耗時太長。

三. query

查詢數據,能夠根據修改記錄獲取任意commit的數據。

三大部分分離,可以部署為單個服務,也可以解耦為多個服務,便於擴展。

需要解決的問題

  1. 如何保證事件的有序性

CQRS的一個典型問題就是生產端的事件順序和消費端的事件順序不一致,導致數據不一致的問題。如何去解決呢?

Command處理部分處理所有的數據更新部分,會生成一個全局有序的commitid,代表着更新的順序。也就是生產端的事件順序,但是到達我們消費端的順序卻不一定是這個順序。所以消費端,事件處理完成后,會更新消費的最新commitid。如果當前事件的commitid小於最新的commitid,事件遺棄。

  1. 如何保證讀數據性能
    event handle部分會去合並commit,所以讀數據不是從所有的修改數據commit中合並數據。數據已經預先處理了,所以會大大加快讀取效率,可以控制待合並的數據在5~10commits范圍之內。

  2. 數據會丟失嗎

系統分離后,沒有事務保證,數據的完整性如何保證。

當數據更新Command寫入成功后,代表這條數據更新成功,這個數據就不會丟失。因為這些數據都已經被持久化了,剩下的問題就是讀取這些提交的Command Commit。我們可以通過合並這些commit,得到最新的完整數據。所以即使event-handle部分宕機了,仍然可以讀取到最新的數據。

說明

這個案例還是沒有應用框架,調研過axon,評估目前還不是太適合用,代碼可讀性不強,帶來的好處不明顯。后續再考慮是否需要引入框架。

DDD系列

我們團隊是如何落地DDD的(1)

可落地的DDD的(2)-為什么說MVC工程架構已經過時

可落地的DDD(3)-如何利用DDD進行微服務的划分

可落地的DDD(4)-如何利用DDD進行微服務的划分(2)

可落地的DDD(5)-戰術設計

如何避免寫出爛的業務代碼(1)-領域對象與領域服務

如何避免寫出爛的業務代碼(2) DDD整改

DDD-CQRS能解什么問題

一次關於聚合根的激烈討論


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM