微服務(wù)模式:業(yè)務(wù)服務(wù)模式
無(wú)論是單體應(yīng)用還是微服務(wù),構(gòu)建企業(yè)應(yīng)用的業(yè)務(wù)邏輯/服務(wù)在更多方面上都有相似之處而不是差異。在兩種方法中,都包含服務(wù)、實(shí)體、倉(cāng)庫(kù)等類。然而,也會(huì)發(fā)現(xiàn)一些明顯的區(qū)別。在本文中,我將試圖以概念性的方式強(qiáng)調(diào)這些區(qū)別,通過(guò)重新審視每種架構(gòu)中內(nèi)置的一些核心設(shè)計(jì)模式和原則。
那么,讓我們從“六邊形架構(gòu)”(Hexagonal Architecture)開(kāi)始,以及它與企業(yè)應(yīng)用業(yè)務(wù)邏輯的關(guān)系。
六邊形架構(gòu)
任何企業(yè)應(yīng)用中的業(yè)務(wù)服務(wù)理論上都在其核心使用了六邊形架構(gòu)
圖01 — 六邊形架構(gòu)
六邊形架構(gòu)/端口和適配器架構(gòu)是一種用于軟件架構(gòu)設(shè)計(jì)的架構(gòu)模式。它旨在創(chuàng)建松散耦合的應(yīng)用組件,可以通過(guò)端口和適配器與其軟件環(huán)境輕松連接。(維基百科)
如圖01所示,“業(yè)務(wù)服務(wù)邏輯”是六邊形架構(gòu)的核心。
領(lǐng)域模型模式
傳統(tǒng)的過(guò)程式事務(wù)腳本模式通常是實(shí)現(xiàn)“簡(jiǎn)單業(yè)務(wù)邏輯”的一種很好的方式。
- 事務(wù)腳本模式:將業(yè)務(wù)邏輯組織成一組每個(gè)類型請(qǐng)求一個(gè)的過(guò)程性事務(wù)腳本。 但是,當(dāng)實(shí)現(xiàn)“復(fù)雜業(yè)務(wù)邏輯”時(shí),應(yīng)考慮使用領(lǐng)域模型模式*,*基本上是使用面向?qū)ο笤O(shè)計(jì)(OOD)。
- 領(lǐng)域模型模式:將業(yè)務(wù)邏輯組織成一個(gè)對(duì)象模型,其中包含具有狀態(tài)和行為的類[1]。
領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD)
然而,領(lǐng)域模型模式在典型的單體應(yīng)用后端上效果良好,但在微服務(wù)應(yīng)用中有一定局限性,這基本上由領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD)所覆蓋。
DDD是對(duì)OOD的細(xì)化,它是一種開(kāi)發(fā)復(fù)雜后端業(yè)務(wù)邏輯的方法。 使用DDD時(shí),每個(gè)服務(wù)都有其自己的領(lǐng)域模型,避免了整個(gè)應(yīng)用程序的統(tǒng)一領(lǐng)域模型的問(wèn)題。
戰(zhàn)略模式與戰(zhàn)術(shù)模式
DDD提出了多種戰(zhàn)略模式和戰(zhàn)術(shù)模式。
其中兩個(gè)關(guān)鍵的戰(zhàn)略模式是子域(Subdomains)和有界上下文(Bounded Contexts)。這些模式通常有助于在應(yīng)用程序中分解業(yè)務(wù)邏輯。
根據(jù)Vaughn Vernon的《實(shí)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》一書[5],子域存在于問(wèn)題空間,有界上下文存在于解決方案空間。 換句話說(shuō),有界上下文幫助您管理應(yīng)用程序中的復(fù)雜性,而子域則有助于組織和管理業(yè)務(wù)域的不同方面。 在實(shí)踐中,有界上下文通常與一個(gè)子域?qū)R,但也可能在單個(gè)子域內(nèi)有多個(gè)有界上下文,或者有一個(gè)跨越多個(gè)子域的有界上下文。 在每個(gè)有界上下文中,我們可以建立專門負(fù)責(zé)各自領(lǐng)域的團(tuán)隊(duì)來(lái)進(jìn)行管理。這些團(tuán)隊(duì)負(fù)責(zé)構(gòu)建給定領(lǐng)域的構(gòu)件、需求、規(guī)范和服務(wù)。 戰(zhàn)術(shù)模式基本上是您在服務(wù)中定義的領(lǐng)域模型的構(gòu)建塊。其中一些戰(zhàn)術(shù)設(shè)計(jì)模式是實(shí)體(Entity)、值對(duì)象(Value Object)、工廠(Factory)、倉(cāng)庫(kù)(Repository)、服務(wù)(Service)和聚合(Aggregate)。 在本文中,我們將更深入地研究聚合模式及其在典型微服務(wù)設(shè)計(jì)中的用途。
聚合模式
聚合模式:將一個(gè)領(lǐng)域模型組織為一組聚合,每個(gè)聚合都是一個(gè)可以視為單元的對(duì)象圖[1] 傳統(tǒng)的領(lǐng)域模型是一個(gè)類和它們之間的關(guān)系的集合。在這個(gè)模型中,所有類和關(guān)系都是相互關(guān)聯(lián)的,相對(duì)較難找到每個(gè)業(yè)務(wù)對(duì)象的邊界,這是復(fù)雜微服務(wù)設(shè)計(jì)的關(guān)鍵要求。DDD中的聚合模式可以幫助您解決這個(gè)問(wèn)題。 在聚合模式中,根據(jù)定義,將領(lǐng)域模型結(jié)構(gòu)化為一組聚合使其邊界顯式并更易于理解。
每個(gè)聚合都有一個(gè)根實(shí)體(聚合根),可能有一個(gè)或多個(gè)值對(duì)象。
但這并不意味著一個(gè)聚合只能有一個(gè)實(shí)體。您可以在一個(gè)聚合中有多個(gè)實(shí)
體。但最佳實(shí)踐是在一個(gè)聚合內(nèi)有最少數(shù)量的實(shí)體,以提高每個(gè)事務(wù)的可擴(kuò)展性。
聚合根是主要實(shí)體,它保存對(duì)領(lǐng)域模型中其他聚合的引用,并且是唯一一個(gè)可以用于直接查找的聚合中的實(shí)體。在聚合中的組件(例如值對(duì)象)將彼此間有對(duì)象引用。在圖02中,您將看到這一點(diǎn),每個(gè)引用的聚合主鍵ID都存儲(chǔ)在主要聚合中,即聚合01。這允許在領(lǐng)域模型內(nèi)部實(shí)現(xiàn)更松散耦合的架構(gòu)。
聚合通常是從數(shù)據(jù)庫(kù)完整加載(以避免任何延遲加載)。即使在它被刪除的同時(shí),聚合也會(huì)將其邊界內(nèi)的所有對(duì)象從數(shù)據(jù)庫(kù)中移除。除此之外,將它們存儲(chǔ)在像MongoDB這樣的NoSQL數(shù)據(jù)庫(kù)中更加簡(jiǎn)單。
簡(jiǎn)而言之,應(yīng)用DDD聚合模式將:
- 將服務(wù)中的領(lǐng)域模型模塊化。
- 消除服務(wù)之間的對(duì)象引用(在DDD中,不同聚合中的類之間的引用是基于主鍵值而不是對(duì)象引用)。
- 事務(wù)只能創(chuàng)建或更新單個(gè)聚合。這允許應(yīng)用程序使用Saga模式更新多個(gè)聚合。
聚合與Saga模式
Saga編排了一系列(微)服務(wù)中的本地事務(wù),以保持?jǐn)?shù)據(jù)一致性。每個(gè)本地事務(wù)都與一個(gè)映射的聚合相關(guān)聯(lián)(參見(jiàn)圖03)。
圖03 — 連接聚合模式和Saga模式
聚合與有界上下文
在技術(shù)理論上,有關(guān)“有界上下文”和“聚合”之間的區(qū)別有一些誤解。因此,了解它們之間的區(qū)別及其與微服務(wù)的關(guān)聯(lián)至關(guān)重要。
如前所述,微服務(wù)可以通過(guò)“有界上下文”或“領(lǐng)域”來(lái)解釋。每個(gè)“有界上下文”將有一個(gè)或多個(gè)“聚合”。
圖04 — 有界上下文與聚合
因此,在實(shí)踐中,微服務(wù)不應(yīng)小于一個(gè)聚合,也不應(yīng)大于一個(gè)有界上下文。
領(lǐng)域事件模式
在概念上,當(dāng)聚合被創(chuàng)建和更新時(shí),它們會(huì)發(fā)布領(lǐng)域事件。聚合知道其狀態(tài)何時(shí)發(fā)生變化,因此知道要發(fā)布的事件。
這些領(lǐng)域事件最終作為消息發(fā)布到消息代理(例如Kafka)。
領(lǐng)域事件模式:當(dāng)聚合被創(chuàng)建并且經(jīng)歷某些其他重要變化時(shí),發(fā)布領(lǐng)域事件。
事件風(fēng)暴
有幾種策略可以識(shí)別領(lǐng)域事件。其中一種流行的策略是事件風(fēng)暴,可以通過(guò)一種研討會(huì)形式的安排來(lái)執(zhí)行,以了解具有許多事件的復(fù)雜領(lǐng)域。這種研討會(huì)的最終結(jié)果是一個(gè)以事件為中心的領(lǐng)域模型,其中包含聚合和事件。