本文是將介紹如何在微服務中實施CQRS模式,并深入探討為什么無服務器和這種類型的系統無比契合。在最后,將介紹一個使用Spring Cloud Stream實施CQRS的參考應用。
什么是事件驅動型架構?
事件驅動型架構會優先處理領域事件,但這種架構已經逐漸被淘汰。
我們日常使用的一個示例是前端應用。在如今使用的Web瀏覽器中,事件的處理方法是捕獲用戶表單的輸入數據,而連接到頁面元素的事件將由一個顯式映射函數來處理,在觸發時在用戶界面應用對狀態的更改。
最近,隨著微服務的廣泛普及,人們對如何在分布式后端系統中利用事件驅動技術重新產生了興趣。
CQRS
如今,事件驅動型架構中最熱門的實踐之一叫做CQRS,全稱是命令查詢責任分離。CQRS是一種架構風格,能讓您使用不同模型來更新和讀取領域數據。
CQRS的基本理念是,您用來更新和讀取數據的模型要相互分離是很自然的事情。上圖描述了這種基本思想。
CQRS之所以在事件驅動型架構中如此受歡迎,是因為作為輸入的領域事件與其所屬的領域模型在結構上有所差異。以下面這個代表一個帳戶的領域模型對象為例。
示例1.帳戶整合
{
"createdAt":1481351048967,
"lastModified":1481351049385,
"userId":1,
"accountNumber":"123456",
"defaultAccount": true,
"status":"ACCOUNT_ACTIVE"
}
當某個服務想查詢帳戶時,就會使用該模型。那么,如果我們要將狀態更新為ACCOUNT_SUSPENDED,該怎么辦?通常,只需簡單更新領域對象的狀態字段即可。現在,如果我們想使用領域事件來更新狀態,該怎么辦?由于領域對象在結構上與事件不同,我們需要一個可將不同模型作為命令接受的API。
以下代碼段是將帳戶狀態從ACCOUNT_ACTIVE轉換為ACCOUNT_SUSPENDED的領域事件。
示例2.帳戶事件
{
"createdAt":1481353397395,
"lastModified":1481353397395,
"type":"ACCOUNT_SUSPENDED",
"accountNumber":"123456"
}
要處理此領域事件并將更新應用到查詢模型,我們必須有接受命令的API。該命令將包含領域事件的模型,并使用模型來處理對帳戶查詢模型的更新。
將命令模型與查詢模型相分離是對CQRS最簡單的解釋。我們如今常見的復雜性更多地與實施類型有關,將模式應用到微服務時尤為如此。
CQRS和微服務
如果CQRS與微服務相結合,毫不夸張地說,情況就變得有點復雜了。我們來看看使用Spring Boot實施CQRS的“簡單”微服務是什么樣。
上圖是CQRS模式實施的簡略圖示。圖中,我們將一個微服務分為命令端、查詢端和事件處理器,這三個部分可以相互獨立地部署。
命令端
本示例中的命令端提供了REST API,可接受通過HTTP發送的請求。請求采取命令的形式,可以驅動對微服務所擁有的領域數據的狀態更改。簡單來說,對領域數據的任何寫入都將以命令形式從API請求流出,處理導致數據庫發生更改的操作。
命令觸發操作,操作觸發領域事件。領域事件保存在事件存儲中,也就是“一個將數據庫與消息代理相結合的系統。”最合適入門使用的事件存儲是Eventuate,是由Chris Richardson創建的項目,旨在幫助將CQRS和Event Sourcing應用到微服務。
領域事件存儲為按時間順序排列的一系列事件,附加在日志上。由于每個命令都生成一個事件,我們能夠根據收集的事件歷史記錄重新構建當前系統的總體狀態。
事件處理器