最全面微服務教程:SpringBoot + DDD + Apache Kafka實現最終一致性 - itnext
這是關于如何使用Spring for Apache Kafka在跨多個微服務的MongoDB中管理分布式數據模型。
由多個微服務組成的現代分布式系統,每個微服務都擁有一個領域的聚合數據的子集,那么該系統幾乎肯定會具有某些數據重復,在這種情況下,我們如何保持數據的一致性?
Apache Kafka
Apache Kafka是一個開放源代碼的分布式事件流平臺,能夠處理數萬億條消息。根據Confluent(最初被認為是消息隊列)的說法,Kafka基于分布式提交日志的抽象。自2011年由LinkedIn創建并開源以來,Kafka已從消息傳遞隊列迅速發展為成熟的事件流平臺。
根據Wikipedia的說法,最終一致性是一種用于分布式計算以實現高可用性的一致性模型,該模型非正式地保證了如果不對給定數據項進行任何新的更新,則最終對該項的所有訪問都將返回最后的更新值。
領域驅動設計
為了進行討論,讓我們研究一個常見的示例:在線店面。
使用域驅動設計(DDD)方法,我們希望問題域(在線店面)由多個有界上下文組成。綁定的上下文可能包括購物Order、客戶服務、市場營銷、安全性、送貨Fullfillment、會計等。
給定這個問題域,我們可以假設我們擁有客戶的概念。此外,我們可以假設定義客戶的唯一屬性可能分布在多個有界上下文中。完整的客戶視圖將要求您匯總來自多個上下文的數據,例如:
- 會計方面可能是記錄系統的主要客戶信息,如客戶的姓名,聯系方式,聯系方式偏好,以及計費和送貨地址。
- 市場營銷可能會擁有有關客戶使用商店的忠誠度計劃和在線購物活動的其他信息。
- 送貨上下文可能會保留所有運送給客戶的訂單的記錄。
- 安全性可能會保留客戶的訪問憑據,帳戶訪問歷史記錄和隱私設置。
分布式數據一致性
我們域數據模型需要跨有界上下文甚至是同一上下文中的服務之間的某些數據重復,我們必須確保數據的一致性。以客戶更改其家庭住址或電子郵件的情況為例。讓我們假設“會計”上下文是這些數據字段的記錄系統。但是,要實現訂單送貨,“送貨”上下文可能還需要維護客戶的當前家庭住址。同樣,負責選擇電子郵件廣告的Marketing上下文也需要了解電子郵件的更改并更新其客戶記錄。
如果更改了一條共享數據,則進行更改的一方應負責傳達更改,而不會期望得到響應。因為它們說的是事實,而不是問問題,問問題才需要響應回答,因此,感興趣的各方可以選擇是否以及如何對變更通知采取行動。
這種分離的通信模型通常被描述為事件攜帶狀態轉移,由ThoughtWorks的馬丁·福勒(Martin Fowler)在他有見地的帖子中定義,“事件驅動”是什么意思?。
可以將對數據的更改視為狀態更改事件,即包含更改數據的詳細信息的事件。巧合的是,Fowler在帖子中使用客戶的地址更改作為“事件進行狀態轉移”的示例。格雷厄姆·布魯克斯(Graham Brooks)也在他的帖子中詳細介紹了這一概念,事件攜帶狀態轉移模式。
一致性策略
可以采用多種體系結構方法來解決分布式系統中的數據一致性。例如:
- 您可以使用具有共享模式的單個關系數據庫來持久化數據,而完全避免使用分布式數據模型。但是,可能會爭辯說,使用單個數據庫只會使您的分布式系統變回整體monlith
- 您可以使用變更數據捕獲(CDC)來跟蹤每個數據庫的變更,并將這些變更的記錄發送到Kafka主題,以供感興趣的各方使用。
- Kafka Connect是一個很好的選擇,正如Confluent的Robin Moffatt所著的文章“不再孤島:
- 如何將數據庫與Apache Kafka和CDC集成”中所述
- 我們可以使用獨立于域的其他業務服務的單獨的數據服務,其唯一作用是確保跨域的數據一致性。如果消息仍然存在于Kafka中,則該服務具有通過消息重播提供數據可審核性的附加功能。當然,另一組服務會增加系統的操作復雜性。
- 在此帖子的某種程度的簡化架構中,業務微服務將通過生產和使用來自其所訂閱的多個Kafka主題的消息來維護其各自域之間的一致性。Kafka生產者也可能是我們領域內的消費使用者。
店面示例
在這篇文章中,我們的網上商店API將使用Java構建Spring Boot和OpenJDK的16。我們將通過使用保證分布式數據的一致性發布/訂閱模式與Spring的Apache kafka項目。當一塊數據由一個Spring Boot微服務改變,如果合適的話,該狀態改變將觸發一個狀態改變事件,這將使用卡夫卡主題與其他微服務共享。
店面訂購過程的視圖顯示在下面的圖所示。箭頭表示數據的交換。卡夫卡將作為從一個去耦服務的其他同時仍能確保數據分布的一種手段。鑒于訂購的使用情況下,我們將研究的三種服務是構成我們的店面API的交互:會計界范圍內的賬戶服務,履行范圍內的配送服務,訂單管理范圍內的訂單服務。我們將研究三個服務如何使用卡夫卡通信狀態的變化完全完全的方式(改變他們的數據)給對方。
下面示出了圖中的事件在后討論的子系統之間流動。下面對應的編號,以上述訂購過程的編號。我們將著眼于三個事件流2,5和6。我們將模擬事件流3,由購物車服務中創建的訂單。店面微服務
我們將探索這三種微服務中每一種的功能,以及它們如何使用Kafka 2.8共享狀態改變事件。每個店面API服務都是使用Spring Boot 2.0和Gradle構建的。每個Spring Boot服務包括Spring Data REST,Spring Data MongoDB,用于Apache Kafka的spring-cloud-sleuth,SpringFox和Spring Boot Actuator。為了簡單起見,Kafka Streams和Spring Cloud Stream的使用不屬于本文的一部分。
源代碼
店面的微服務源代碼可在GitHub上公開獲得。可以使用以下命令克隆四個GitHub項目: |
git clone --branch 2021-istio \ --single-branch --depth 1 \ https://github.com/garystafford/storefront-demo-accounts.git git clone --branch 2021-istio \ --single-branch --depth 1 \ https://github.com/garystafford/storefront-demo-orders.git git clone --branch 2021-istio \ --single-branch --depth 1 \ https://github.com/garystafford/storefront-demo-fulfillment.git git clone --branch 2021-istio \ --single-branch --depth 1 \ https://github.com/garystafford/storefront-demo.git