學習什麼是領域事件.何時而且爲何要使用領域事件。 •學習如何將領域事件建模成對象,什麼時候應該爲領域事件建立惟一的身份標識。 •學習一個輕量級的發佈-訂閱[Gamma et al]模式。 •學習哪些組件用於發佈事件,哪些組件用於訂閱事件。 •學習爲何咱們須要一個事件存儲.如何實現事件存儲、如何使用事件存儲。 •學習S aaSOvation團隊是如何經過不一樣的方式將領域事件發佈給自治系統前端
使用領域事件來建模發生在領域中的一些事情。這是一個功能強大的建模工具,讓人愛不釋手。 使用領域事件時,首先就是要對不一樣事件進行定義。數據庫
《領域驅動設計》一書中並未給出領域事件的定義。由於該模型是在該書出版後才被提出。 當前對領域事件的定義:領域專家所關心的發生在領域中的一些事件。 將領域中所發生的活動建模成一系列的離散事件。每一個事件都用領域對象來表 示……領域事件是領域模型的組成部分,表示領域中所發生的事情。[Evans, Ref, P-20] 一markdown
個領域事件將致使進一步的業務操做,在實現業務解耦的同時,還有助於造成完整的業務閉環。網絡
領域事件能夠是業務流程的一個步驟,好比一個事件發生後觸發的後續動做,好比密碼連續輸錯三次,觸發鎖定帳戶的動做。架構
在這些場景中,若是發生某種事件後,會觸發進一步的操做,那麼這個事件極可能就是領域事件。因爲領域事件須要發佈到外部系統,好比發佈到另外一個限界上下文。因爲這樣的事件由訂閱方處理,它將對本地和遠程上下文產生深遠的影響。併發
那領域事件爲何要用最終一致性,而不是傳統SOA的直接調用?異步
聚合的一個原則:一個事務中最多隻能更改一個聚合實例。因此分佈式
聚合建立併發布事件。訂閱方能夠先存儲事件,而後再將其轉發到遠程訂閱方,或不經存 儲,直接轉發。除非MQ共享了模型的數據存儲,否則即時轉發須要XA(兩階段提交)。微服務
考慮在系統非高峯時期,批處理過程一般進行一些系統維護工做,好比刪除過時對象、建立新對象以支持新業務需求或通知用戶所發生的重要事件。這樣的批處理過程一般需複雜 查詢且需龐大事務支持。若這些批處理過程存在冗餘會怎麼樣? 系統中發生的每一件事情,咱們都用事件形式捕獲,而後將事件發佈給訂閱方處理,能簡化系統嗎?確定的!它可消除先前批處理過程當中的複雜查詢,由於咱們可以準確知道在什麼時候發生何事,限界上下文也由此知道接下來應該作啥。在接收到領域事件時,系統可當即處理。本來批量集中處理的過程能夠分散成許多粒度較小的處理單元,業務需求也由此更快知足,用戶也可及時進行下一步操做。工具
領域事件驅動設計可切斷領域模型之間的強依賴。 事件發佈完成後,發佈方沒必要關心後續訂閱方事件處理是否成功,便可實現領域模型的解耦,維護領域模型的獨立性和數據一致性。 在領域模型映射到微服務架構時,領域事件可解耦微服務,微服務間的數據沒必要要求強一致性,而是基於事件的最終一致性。
領域事件由外部命令觸發。觸發命令能夠是領域服務,也能夠是實體的某一個方法或者行爲。
走canal增量同步數據庫數據,經過監聽特定表的數據變動來觸發生成事件的調用。如此有利於主流業務的解耦,提升維護和可讀性。(具體生成事件的操做固然仍是放在對應領域的微服務中,canal監聽消費端能夠理解爲一個任務調度平臺)。這樣的實現邏輯相對簡單。
那不一樣領域事件,如何處理呢?
領域事件發生在微服務內的聚合間,領域事件發生後完成事件實體的構建和事件數據持久化,發佈方聚合將事件發佈到事件總線,訂閱方接收事件數據完成後續業務操做。
微服務內大部分事件的集成,都發生在同一進程,進程自身便可控制事務。但一個事件若同時更新多個聚合,按一次事務只更新一個聚合原則,可考慮引入事件總線。
微服務內應用服務,可經過跨聚合的服務編排和組合,以服務調用方式完成跨聚合訪問,這種方式一般應用於實時性和數據一致性要求高的場景。這個過程會用到分佈式事務,以保證發佈方和訂閱方的數據同時更新成功。
在微服務內,不是說少用領域事件,而是推薦少用事件總線。DDD是以聚合爲單位進行數據管理,若一次操做會修改同一微服務內的多個聚合的數據,就需保證多個聚合的數據一致性。 爲了解耦不一樣聚合,需採用分佈式事務或事件總線,而事件總線不太方便管理服務和數據的關係,可用相似saga之類的分佈式事務技術。總之需確保不一樣聚合的業務規則和數據一致性。
跨微服務的領域事件會在不一樣限界上下文或領域模型間實現業務協做,主要爲解耦,減輕微服務間實時服務訪問壓力。
領域事件發生在微服務間較多,事件處理機制也更復雜。跨微服務事件可推進業務流程或數據在不一樣子域或微服務間直接流轉。
跨微服務的事件機制要整體考慮事件構建、發佈和訂閱、事件數據持久化、MQ,甚至事件數據持久化時還可能需考慮引入分佈式事務。
微服務間訪問也可採用應用服務直接調用,實現數據和服務的實時訪問,弊端就是跨微服務的數據同時變動須要引入分佈式事務。分佈式事務會影響系統性能,增長微服務間耦合,儘可能避免使用。
至少包括以下:
即主要記錄事件自己以及事件發生背景的數據。
記錄事件發生那刻的業務數據,這些數據會隨事件傳輸到訂閱方,以開展後續業務操做。
事件基本屬性和業務屬性一塊兒構成事件實體,事件實體依賴聚合根。領域事件發生後,事件中的業務數據再也不修改,所以業務數據能夠以序列化值對象的形式保存,這種存儲格式在消息中間件中也比較容易解析和獲取。
爲保證事件結構的統一,一般建立事件的基類,子類可自行繼承擴展。因爲事件沒有太多業務行爲,實現通常比較簡單。
事件發佈前需先構建事件實體並持久化。 事件實體的業務數據推薦按需發佈,避免泄露沒必要要業務信息。
當遇到MQ、訂閱方系統宕機或網絡中斷,在問題解決後仍可繼續後續業務流轉,保證數據一致性。 畢竟雖然MQ都有持久化功能,但中間過程或在訂閱到數據後,在處理以前出問題,須要進行數據對帳,這樣就無法找到發佈時和處理後的數據版本。關鍵的業務數據推薦仍是落庫。
實現同一微服務內的聚合之間的領域事件,提供事件分發和接收等服務。 是進程內模型,會在微服務內聚合之間遍歷訂閱者列表,採起同步或異步傳遞數據。
由於在微服務內部在同一個進程,事件總線相對好配置,它能夠配置爲異步的也能夠配置爲同步的。若是是同步就不須要落庫。推薦少用微服務內聚合之間的領域事件,它會增長開發複雜度。 而微服務之間的事件,在事件數據落庫後,經過應用服務直接發佈到MQ。
跨微服務的領域事件大多會用到MQ,實現跨微服務的事件發佈和訂閱。 雖然MQ自身有持久化功能,但中間過程或在訂閱到數據後,在處理以前出問題,須要進行數據對帳,這樣就無法找到發佈時和處理後的數據版本。關鍵的業務數據推薦仍是落庫。
微服務訂閱方在應用層採用監聽機制,接收MQ中的事件數據,完成事件數據的持久化後,就能夠開始進一步的業務處理。領域事件處理可在領域服務中實現。
由於事件發佈方有事件實體的原始的持久化數據,事件訂閱方也有本身接收的持久化數據。通常能夠經過按期對帳的方式檢查數據的一致性。
失敗的狀況應該比例是不多的。失敗的信息可採用屢次重試,若是這個還解決不了,只能將有問題的數據放到一個問題數據區,人工解決。固然要確保一個前提,要保證數據的時序性,不能覆蓋已產生的數據。
通常發佈方不會等待訂閱方反饋結果。發佈方有發佈的事件表,訂閱方有消費事件表,可採用對帳方式發現問題數據。
大型系統的領域事件有不少:
異步的方式通常都有源端和目的端按期對帳的機制。好比採用相似財務衝正的方式。若是在發佈和訂閱之間事件表的數據發現異步數據有問題,須要回退,會有相應的代碼進行數據處理,不過不一樣的場景,業務邏輯會不同,處理的方式會不同。有的甚至還須要轉人工處理。
領域事件在設計時咱們要重點關注領域事件,用領域事件來驅動業務的流轉,儘可能採用基於事件的最終一致,下降微服務之間直接訪問的壓力,實現微服務之間的解耦,維護領域模型的獨立性和數據一致性。
領域事件驅動機制可實現一個發佈方N個訂閱方的模式,這在傳統的直接服務調用設計中基本是不可能作到的。
CQRS主要是想讀寫分離,將沒有領域模型的查詢功能,從命令中分離出來。領域事件主要目的仍是爲了微服務解耦,在連續的業務處理過程當中,以異步化的方式完成下一步的業務處理,下降微服務之間的直連。 它們的共同點就是經過消息中間件實現從源端數據到目的端數據的交互和分離。
若是你就是不想用領域事件,聚合之間還能夠經過應用層來協調和交互。應用服務是全部聚合之上的服務,負責服務的組合和編排,以及聚合之間的協調。
參考