你真的瞭解CQRS嗎

<code>CQRS本身並不是一種架構風格,和最終一致性/消息/讀寫分離/事件溯源/DDD等沒有必然的聯繫。CQRS只是一種非常簡單的模式(pattern),它的最大優勢是CQRS給我們帶來更多的架構屬性選擇/<code> 

CQRS 本質

CQRS 全稱 Command and Query Responsibility Segregation,即命令和查詢職責分離。CQRS 模式的應用非常簡單,如下圖所示

你真的瞭解CQRS嗎

讀接口和寫接口拆分

假設我們的服務為 CustomerService,在非CQRS模式下同時包含了查詢和更新服務接口:

<code>// 根據id查詢消費者Customer GetCustomer(CustomerId)// 根據姓名查詢消費者CustomerSet GetCustomersWithName(Name)// 創建消費者void CreateCustomer(Customer)// 編輯消費者詳情void EditCustomerDetails(CustomerDetails)/<code>

應用CQRS模式之後CustomerService的被拆分成了兩個接口,分別承擔查詢和更新操作:

<code>// CustomerWriteService void CreateCustomer(Customer)void EditCustomerDetails(CustomerDetails)/<code>
<code>// CustomerReadServiceCustomer GetCustomer(CustomerId)CustomerSet GetCustomersWithName(Name)/<code>

以上這種簡單的分離就是CQRS模式的全部了,是不是非常簡單?確實,單純的看,CQRS的確就是這麼簡單。

另外,從上述的示例我們還可看出CQRS的一個特點:

  • 查詢職責值獲取數據,返回查詢數據,但不改變數據狀態
  • 命令直著改變數據狀態,不返回任何數據
<code>是否嚴格遵循上述約定存在爭議,像棧這種數據結構顯然是不符合如上約定的。"出棧" 操作同時改變棧狀態和返回數據。/<code> 

CQRS最大優勢就是基於這種職責分離能帶給我們更多的架構屬性選擇。

1. “讀” 和 “寫” 兩側進行獨立部署以獲取更好的伸縮性

2. “讀” 和 “寫” 兩側獨立架構

3. “讀” 和 “寫” 兩側進行獨立數據模型

基於CQRS,我們可以衍生出更多的架構屬性,結合實際的業務場景,進行差異化的架構設計。

CQRS 和 消息模式

CQRS和消息模式沒有必然聯繫,落地CQRS 並不一定需要使用消息模式。

你真的瞭解CQRS嗎

讀寫獨立架構

如果我們採用了CQRS模式,但是命令和查詢兩側底層所依賴的數據模型並未分離,而是基於共享的數據存儲和數據模型,命令和查詢之間不需要額外的交互,命令側的數據更新對查詢側實時可見。在這種架構模式下,兩側基於共享的數據已經天然的集成在一起,不需要額外機制進行通信,自然也無需引入消息了。

如果我們採用CQRS模式,並且命令和查詢兩側進行了數據模型的分離,二者各自依賴獨立的數據模型。同時,數據存儲也分開部署。命令側負責數據的更新,而查詢側只負責數據的查詢,**如何將數據的更新及時同步到查詢側是需要解決的問題**。在這種架構模式下,使用消息模式作為兩側的通信機制是個不錯的選擇,當然,這並不是唯一的選項。

CQRS 和 ES(Event Sourcing, 事件溯源)

ES 並不是一個新的概念,在最早的金融系統中就已經應用。要了解ES,我們需要先看看傳統的數據存儲。在傳統應用中,數據庫例如MySQL(假設存儲介質是數據庫,)中存儲的始終是數據的**最新的狀態**。例如我們對某條用戶的信息進行了多次的修改或編輯,然後保存將數據存儲到數據庫中。無論何時,數據庫中都會記錄最後的、最新的用戶狀態。我們只要根據id或其他信息查詢數據庫中相應的記錄就能獲取該用戶的最新信息。這是應用中典型的數據存儲特點。

<code>當然,我們可以基於特定的數據模型設計以保存數據的更改記錄。/<code>

這種數據存儲模式的特點是簡單,不需要額外的維護複雜的設計,我們能夠非常容易的獲取最新的用戶信息。但是不幸的是,我們丟失了歷史信息,包括用戶的意圖信息。而這些信息則有助於我們進行數據回滾、用戶行為分析以及開發過程中的調試等等。

在ES模式下,數據庫中存儲的不在是數據最新狀態,而是數據的變更記錄,更官方的說法是 “事件(Event)”。數據庫中存儲的數據變化的事件流。我們基於事件流可以對最新狀態進行重建,同時也可以便捷的重現任何歷史節點數據。

ES需要解決大量事件的存儲和高效的實例重建問題,後續單獨的文章再介紹ES。

CQRS 和 Eventual Consistency(最終一致性)

最終一致性也常常在服務之間引入,最終一致性的目的是為了提高擴展性和可用性。CQRS和最終一致性同樣沒有必然的聯繫。往往採用CQRS後,查詢和命令兩側會採用獨立的數據模型,在這種架構模式下,命令側的數據變化後及時同步到查詢側,兩側數據並非實時,在一定的延時後兩側數據最終達成一致。


分享到:


相關文章: