如何構建基於 DDD 領域驅動的微服務?
儘管微服務中的 “微” 一詞表示服務的規模,但它並不是使用微服務的唯一標準。當團隊轉向基於微服務的架構時,他們旨在提高敏捷性以及自主且頻繁地部署功能。很難確定這種架構風格的簡單定義。我喜歡 Adrian Cockcroft 的關於微服務的簡短定義:“面向服務的體系結構,它由鬆散耦合的、具有上下文邊界的元素組成。”
松耦合的面向服務的體系結構,其中每個服務都包含在定義明確的有界上下文中,從而可以快速,頻繁且可靠地交付應用程序。
微服務設計從這些概念中汲取了靈感,因爲所有這些原理都有助於構建可以相互獨立變化和發展的模塊化系統。
在繼續進行之前,讓我們快速瞭解一下 DDD 的一些基本術語。域驅動設計的完整概述超出了本博客的範圍。我們強烈建議任何嘗試構建微服務的人推薦 Eric Evans 的書籍。
微服務與有限上下文如何相關
現在,微服務在哪裏適合?可以說每個有界上下文都映射到微服務嗎?是的,我們將明白爲什麼。在某些情況下,有界上下文的邊界或輪廓可能很大。
考慮上面的例子。定價綁定上下文具有三個不同的模型 - 價格,定價項目和折扣,每個模型負責目錄項目的價格,計算項目列表的總價格並分別應用折扣。我們可以創建一個包含以上所有模型的系統,但是它可能會成爲一個不合理的大型應用程序。如前所述,每個數據模型都有其不變性和業務規則。隨着時間的流逝,如果我們不小心的話,系統可能會變成一個泥濘的大球,邊界模糊,職責重疊,甚至可能回到我們開始的地方—一個整體。
對系統進行建模的另一種方法是將相關模型分離或分組爲單獨的微服務。在 DDD 中,這些模型(價格,定價項目和折扣)被稱爲聚合 Aggregates。聚合是組成相關模型的獨立模型。您只能通過已發佈的界面更改聚合的狀態,並且聚合可確保一致性,並且不變量保持良好狀態。
聚合是關聯對象的集羣,被視爲數據更改的單元。外部引用僅限於 AGGREGATE 的一個成員,稱爲根。一組一致性規則適用於 AGGREGATE 的邊界。推薦一個 Spring Boot 基礎教程及實戰示例:https://www.javastack.cn/categories/Spring-Boot/
上下文映射的完整探索不在本博客的討論範圍之內,但我們將通過一個示例進行說明。下圖顯示了處理電子商務訂單付款的各種應用程序。
-
購物車上下文負責訂單的在線授權;訂單上下文流程過帳付款後的付款流程;聯絡中心會處理所有例外情況,例如重試付款和更改用於訂單的付款方式
-
請注意,這些模型在邏輯上是相同的。也就是說,它們都遵循相同的通用域語言 - 付款方式,授權和結算。只是它們是不同上下文的一部分。
重新定義服務邊界—將聚合映射到正確的上下文
錯誤案例如下圖:
電子商務中所有模型都直接與單個支付聚合的網關上下文(payment gateway context)集成,支付需要保證事務性,但是由於與多個服務集成,支付的事務性就不能通過在各種服務之間強制執行不變性和一致性來實現,(banq 注:當然有人就提出分佈式事務的概念來在這些不同服務之間實現支付過程的事務性,這其實是在錯誤設計基礎上的僞概念)。
另外,分佈式事務系列面試題和答案全部整理好了,微信搜索 Java 技術棧,在後臺發送:面試,可以在線閱讀。
請注意,支付網關中的任何更改都將迫使更改多個服務,並可能更改多個團隊,因爲不同的組可以擁有這些上下文。
進行一些調整並使聚合與正確的上下文對齊,我們可以更好地表示這些子域如下圖。發生了很多變化。讓我們回顧一下更改:
通常,整體 (單體) 或遺留應用程序具有許多聚合,通常具有重疊的邊界。創建這些聚合及其依賴關係的上下文地圖有助於我們瞭解將要從這些整體中擺脫出來的任何新微服務的輪廓。請記住,微服務架構的成功或失敗取決於聚合之間的低耦合以及這些聚合之間的高內聚性。
同樣重要的是要注意,有界上下文本身就是合適的內聚單元。即使上下文具有多個聚合,整個上下文及其聚合也可以組成一個微服務。我們發現這種啓發式方法對於有些晦澀的領域特別有用 - 考慮組織正在涉足的新業務領域。您可能對分離的正確邊界沒有足夠的瞭解,並且聚集體的任何過早分解都可能導致昂貴的重構。想象一下,由於數據遷移,不得不將兩個數據庫合併爲一個,因爲我們偶然發現兩個聚合屬於同一類。但是請確保通過接口將這些聚合充分隔離,以使它們不知道彼此的複雜細節。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/kYUXUzxPNP51WLf0uKWlrw