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