微服務(wù)架構(gòu):拆分單體應(yīng)用的難點(diǎn)-創(chuàng)新互聯(lián)

拆分單體應(yīng)用為服務(wù)的難點(diǎn)

為金鳳等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及金鳳網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為網(wǎng)站制作、做網(wǎng)站、金鳳網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

從表面上看,通過(guò)定義與業(yè)務(wù)能力或子域相對(duì)應(yīng)的服務(wù)來(lái)創(chuàng)建微服務(wù)架構(gòu)的策略看起來(lái)很簡(jiǎn)單。但是,你可能會(huì)遇到幾個(gè)障礙:

  • 網(wǎng)絡(luò)延遲。

  • 同步進(jìn)程間通信導(dǎo)致可用性降低。 

  • 在服務(wù)之間維持?jǐn)?shù)據(jù)一致性。

  • 獲取一致的數(shù)據(jù)視圖。

  • 上帝類阻礙了拆分。

讓我們來(lái)看看每個(gè)問(wèn)題,先從網(wǎng)絡(luò)延遲開(kāi)始。

網(wǎng)絡(luò)延遲

網(wǎng)絡(luò)延遲是分布式系統(tǒng)中一直存在的問(wèn)題。你可能會(huì)發(fā)現(xiàn),對(duì)服務(wù)的特定分解會(huì)導(dǎo)致兩個(gè)服務(wù)之間的大量往返調(diào)用。有時(shí),你可以通過(guò)實(shí)施批處理API在一次往返中獲取多個(gè)對(duì)象,從而將延遲減少到可接受的數(shù)量。但在其他情況下,解決方案是把多個(gè)相關(guān)的服務(wù)組合在一起,用編程語(yǔ)言的函數(shù)調(diào)用替換昂貴的進(jìn)程間通信。

同步進(jìn)程間通信導(dǎo)致可用性降低

另一個(gè)需要考慮的問(wèn)題是如何處理進(jìn)程間通信而不降低系統(tǒng)的可用性。例如,實(shí)現(xiàn)createOrder()操作最常見(jiàn)的方式是讓Order Service使用REST同步調(diào)用其他服務(wù)。這樣做的弊端是REST這樣的協(xié)議會(huì)降低Order Service的可用性。如果任何一個(gè)被調(diào)用的服務(wù)處在不可用的狀態(tài),那么訂單就無(wú)法創(chuàng)建了。有時(shí)候這可能是一個(gè)不得已的折中,但是在第3章中學(xué)習(xí)異步消息之后,你就會(huì)發(fā)現(xiàn)其實(shí)有更好的辦法來(lái)消除這類同步調(diào)用產(chǎn)生的緊耦合并提升可用性。

在服務(wù)之間維持?jǐn)?shù)據(jù)一致性

另一個(gè)挑戰(zhàn)是如何在某些系統(tǒng)操作需要更新多個(gè)服務(wù)中的數(shù)據(jù)時(shí),仍舊維護(hù)服務(wù)之間的數(shù)據(jù)一致性。例如,當(dāng)餐館接受訂單時(shí),必須在Kitchen Service和Delivery Service中同時(shí)進(jìn)行更新。Kitchen Service會(huì)更改Ticket的狀態(tài)。Delivery Service安排訂單的交付。這些更新都必須以原子化的方式完成。

傳統(tǒng)的解決方案是使用基于兩階段提交(two phase commit)的分布式事務(wù)管理機(jī)制。但正如你將在第4章中看到的那樣,對(duì)于現(xiàn)今的應(yīng)用程序而言,這不是一個(gè)好的選擇,你必須使用一種非常不同的方法來(lái)處理事務(wù)管理,這就是Saga。Saga是一系列使用消息協(xié)作的本地事務(wù)。Saga比傳統(tǒng)的ACID事務(wù)更復(fù)雜,但它們?cè)谠S多情況下都能工作得很好。Saga的一個(gè)限制是它們最終是一致的。如果你需要以原子方式更新某些數(shù)據(jù),那么它必須位于單個(gè)服務(wù)中,這可能是分解的障礙。

獲取一致的數(shù)據(jù)視圖

分解的另一個(gè)障礙是無(wú)法跨多個(gè)數(shù)據(jù)庫(kù)獲得真正一致的數(shù)據(jù)視圖。在單體應(yīng)用程序中,ACID事務(wù)的屬性保證查詢將返回?cái)?shù)據(jù)庫(kù)的一致視圖。相反,在微服務(wù)架構(gòu)中,即使每個(gè)服務(wù)的數(shù)據(jù)庫(kù)是一致的,你也無(wú)法獲得全局一致的數(shù)據(jù)視圖。如果你需要一些數(shù)據(jù)的一致視圖,那么它必須駐留在單個(gè)服務(wù)中,這也是服務(wù)分解所面臨的問(wèn)題。幸運(yùn)的是,在實(shí)踐中這很少帶來(lái)真正的問(wèn)題。

上帝類阻礙了拆分

分解的另一個(gè)障礙是存在所謂的上帝類。上帝類是在整個(gè)應(yīng)用程序中使用的全局類。上帝類通常為應(yīng)用程序的許多不同方面實(shí)現(xiàn)業(yè)務(wù)邏輯。它有大量字段映射到具有許多列的數(shù)據(jù)庫(kù)表。大多數(shù)應(yīng)用程序至少有一個(gè)這樣的上帝類,每個(gè)類代表一個(gè)對(duì)領(lǐng)域至關(guān)重要的概念:銀行賬戶、電子商務(wù)訂單、保險(xiǎn)政策,等等。因?yàn)樯系垲悓?yīng)用程序的許多不同方面的狀態(tài)和行為捆綁在一起,所以將使用它的任何業(yè)務(wù)邏輯拆分為服務(wù)往往都是一個(gè)不可逾越的障礙。

Order類是FTGO應(yīng)用程序中上帝類的一個(gè)很好的例子。這并不奇怪:畢竟FTGO的目的是向客戶提供食品訂單。系統(tǒng)的大多數(shù)部分都涉及訂單。如果FTGO應(yīng)用程序具有單個(gè)領(lǐng)域模型,則Order類將是一個(gè)非常大的類。它將具有與應(yīng)用程序的許多不同部分相對(duì)應(yīng)的狀態(tài)和行為。圖6顯示了使用傳統(tǒng)建模技術(shù)創(chuàng)建的Order類的結(jié)構(gòu)。

微服務(wù)架構(gòu):拆分單體應(yīng)用的難點(diǎn)

圖6 Order這個(gè)上帝類承載了太多的職責(zé)

如你所見(jiàn),Order類具有與訂單處理、餐館訂單管理、送餐和付款相對(duì)應(yīng)的字段及方法。由于一個(gè)模型必須描述來(lái)自應(yīng)用程序的不同部分的狀態(tài)轉(zhuǎn)換,因此該類還具有復(fù)雜的狀態(tài)模型。在目前情況下,這個(gè)類的存在使得將代碼分割成服務(wù)變得極其困難。

一種解決方案是將Order類打包到庫(kù)中并創(chuàng)建一個(gè)中央Order數(shù)據(jù)庫(kù)。處理訂單的所有服務(wù)都使用此庫(kù)并訪問(wèn)訪問(wèn)數(shù)據(jù)庫(kù)。這種方法的問(wèn)題在于它違反了微服務(wù)架構(gòu)的一個(gè)關(guān)鍵原則,并導(dǎo)致我們特別不愿意看到的緊耦合。例如,對(duì)Order模式的任何更改都要求其他開(kāi)發(fā)團(tuán)隊(duì)同步更新和重新編譯他們的代碼。

另一種解決方案是將Order數(shù)據(jù)庫(kù)封裝在Order Service中,該服務(wù)由其他服務(wù)調(diào)用以檢索和更新訂單。該設(shè)計(jì)的問(wèn)題在于這樣的一個(gè)Order Service將成為一個(gè)純數(shù)據(jù)服務(wù),成為包含很少或沒(méi)有業(yè)務(wù)邏輯的貧血領(lǐng)域模型(anemic domain model)。這兩種解決方案都沒(méi)有吸引力,但幸運(yùn)的是,DDD提供了一個(gè)好的解決方案。

更好的方法是應(yīng)用DDD并將每個(gè)服務(wù)視為具有自己的領(lǐng)域模型的單獨(dú)子域。這意味著FTGO應(yīng)用程序中與訂單有關(guān)的每個(gè)服務(wù)都有自己的領(lǐng)域模型及其對(duì)應(yīng)的Order類的版本。Delivery Service是多領(lǐng)域模型的一個(gè)很好的例子。如圖7所示為Order,它非常簡(jiǎn)單:取餐地址、取餐時(shí)間、送餐地址和送餐時(shí)間。此外,DeliveryService使用更合適的Delivery名稱,而不是稱之為Order。

微服務(wù)架構(gòu):拆分單體應(yīng)用的難點(diǎn)

圖7 Delivery Service的領(lǐng)域模型

Delivery Service對(duì)訂單的任何其他屬性不感興趣。

Kitchen Service有一個(gè)更簡(jiǎn)單的訂單視圖。它的Order版本就是一個(gè)Ticket(后廚工單)。如圖8所示,Ticket只包含status、requestedDeliveryTime、prepareByTime以及告訴餐館準(zhǔn)備的訂單項(xiàng)列表。它不關(guān)心消費(fèi)者、付款、交付等這些與它無(wú)關(guān)的事情。

微服務(wù)架構(gòu):拆分單體應(yīng)用的難點(diǎn)

圖8 Kitchen Service的領(lǐng)域模型

Order Service具有最復(fù)雜的訂單視圖,如圖9所示。即使它有相當(dāng)多的字段和方法,它仍然比原始版本的那個(gè)Order上帝類簡(jiǎn)單得多。

微服務(wù)架構(gòu):拆分單體應(yīng)用的難點(diǎn)

圖9 Order Service的領(lǐng)域模型

每個(gè)領(lǐng)域模型中的Order類表示同一Order業(yè)務(wù)實(shí)體的不同方面。FTGO應(yīng)用程序必須維持不同服務(wù)中這些不同對(duì)象之間的一致性。例如,一旦OrderService授權(quán)消費(fèi)者的信用卡,它必須觸發(fā)在Kitchen Service中創(chuàng)建Ticket。同樣,如果Kitchen Service拒絕訂單,則必須在Order Service中取消訂單,并且為客戶退款。在第4章中,我們將學(xué)習(xí)如何使用前面提到的事件驅(qū)動(dòng)機(jī)制Saga來(lái)維護(hù)服務(wù)之間的一致性。

除了造成一些技術(shù)挑戰(zhàn)以外,擁有多個(gè)領(lǐng)域模型還會(huì)影響用戶體驗(yàn)。應(yīng)用程序必須在用戶體驗(yàn)(即其自己的領(lǐng)域模型)與每個(gè)服務(wù)的領(lǐng)域模型之間進(jìn)行轉(zhuǎn)換。例如,在FTGO應(yīng)用程序中,向消費(fèi)者顯示的Order狀態(tài)來(lái)自存儲(chǔ)在多個(gè)服務(wù)中的Order信息。這種轉(zhuǎn)換通常由API Gateway處理,將在第8章中討論。盡管存在這些挑戰(zhàn),但在定義微服務(wù)架構(gòu)時(shí),必須識(shí)別并消除上帝類。

我們現(xiàn)在來(lái)看看如何定義服務(wù)API。

6 定義服務(wù)API

到目前為止,我們有一個(gè)系統(tǒng)操作列表和一個(gè)潛在服務(wù)列表。下一步是定義每個(gè)服務(wù)的API:也就是服務(wù)的操作和事件。存在服務(wù)API操作有以下兩個(gè)原因:首先,某些操作對(duì)應(yīng)于系統(tǒng)操作。它們由外部客戶端調(diào)用,也可能由其他服務(wù)調(diào)用。另次,存在一些其他操作用以支持服務(wù)之間的協(xié)作。這些操作僅由其他服務(wù)調(diào)用。

服務(wù)通過(guò)對(duì)外發(fā)布事件,使其能夠與其他服務(wù)協(xié)作。第4章將描述如何使用事件來(lái)實(shí)現(xiàn)Saga,這些Saga可以維護(hù)服務(wù)之間的數(shù)據(jù)一致性。第7章將討論如何使用事件來(lái)更新CQRS視圖,這些視圖支持有效的查詢。應(yīng)用程序還可以使用事件來(lái)通知外部客戶端。例如,可以使用WebSockets將事件傳遞給瀏覽器。

定義服務(wù)API的起點(diǎn)是將每個(gè)系統(tǒng)操作映射到服務(wù)。之后確定服務(wù)是否需要與其他服務(wù)協(xié)作以實(shí)現(xiàn)系統(tǒng)操作。如果需要協(xié)作,我們將確定其他服務(wù)必須提供哪些API才能支持協(xié)作。首先來(lái)看一下如何將系統(tǒng)操作分配給服務(wù)。

把系統(tǒng)操作分配給服務(wù)

第一步是確定哪個(gè)服務(wù)是請(qǐng)求的初始入口點(diǎn)。許多系統(tǒng)操作可以清晰地映射到服務(wù),但有時(shí)映射會(huì)不太明顯。例如,考慮使用noteUpdatedLocation()操作來(lái)更新送餐員的位置。一方面,因?yàn)樗c送餐員有關(guān),所以應(yīng)該將此操作分配給Courier Service。另一方面,它是需要送餐地點(diǎn)的DeliveryService。在這種情況下,將操作分配給需要操作所提供信息的服務(wù)是更好的選擇。在其他情況下,將操作分配給具有處理它所需信息的服務(wù)可能是有意義的。表4顯示了FTGO應(yīng)用程序中的哪些服務(wù)負(fù)責(zé)哪些操作。

表4 FTGO應(yīng)用程序的系統(tǒng)操作映射到具體的服務(wù)

微服務(wù)架構(gòu):拆分單體應(yīng)用的難點(diǎn)

把操作分配給服務(wù)后,下一步是確定在處理每一個(gè)系統(tǒng)操作時(shí),服務(wù)之間如何交互。

確定支持服務(wù)協(xié)作所需要的API

某些系統(tǒng)操作完全由單個(gè)服務(wù)處理。例如,在FTGO應(yīng)用程序中,Consumer Service完全獨(dú)立地處理createConsumer()操作。但是其他系統(tǒng)操作跨越多個(gè)服務(wù)。處理這些請(qǐng)求之一所需的數(shù)據(jù)可能分散在多個(gè)服務(wù)周圍。例如,為了實(shí)現(xiàn)createOrder()操作,Order Service必須調(diào)用以下服務(wù)以驗(yàn)證其前置條件并使后置條件成立:

  • Consumer Service:驗(yàn)證消費(fèi)者是否可以下訂單并獲取其付款信息。

  • Restaurant Service:驗(yàn)證訂單行項(xiàng)目,驗(yàn)證送貨地址和時(shí)間是否在餐廳的服務(wù)區(qū)域內(nèi),驗(yàn)證訂單最低要求,并獲得訂單行項(xiàng)目的價(jià)格。

  • Kitchen Service:創(chuàng)建Ticket(后廚工單)。

  • Accounting Service:授權(quán)消費(fèi)者的信用卡。

同樣,為了實(shí)現(xiàn)acceptOrder()系統(tǒng)操作,Kitchen Service必須調(diào)用Delivery Service來(lái)安排送餐員交付訂單。表2-3顯示了服務(wù)、修訂后的API及協(xié)作者。為了完整定義服務(wù)API,你需要分析每個(gè)系統(tǒng)操作并確定所需的協(xié)作。

表5 服務(wù)、修訂后的API及協(xié)作者

微服務(wù)架構(gòu):拆分單體應(yīng)用的難點(diǎn)

微服務(wù)架構(gòu):拆分單體應(yīng)用的難點(diǎn)

總結(jié)

  • 微服務(wù)中的服務(wù)是根據(jù)業(yè)務(wù)需求進(jìn)行組織的,按照業(yè)務(wù)能力或者子域,而不是技術(shù)上的考量。

  • 有兩種分解模式:

        按業(yè)務(wù)能力分解,其起源于業(yè)務(wù)架構(gòu)。

        基于領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的概念,通過(guò)子域進(jìn)行分解。

  • 可以通過(guò)應(yīng)用DDD并為每個(gè)服務(wù)定義單獨(dú)的領(lǐng)域模型來(lái)消除上帝類,正是上帝類引起了阻礙分解的交織依賴項(xiàng)。

本文摘自《微服務(wù)架構(gòu)設(shè)計(jì)模式》,經(jīng)出版方授權(quán)發(fā)布。

分享名稱:微服務(wù)架構(gòu):拆分單體應(yīng)用的難點(diǎn)-創(chuàng)新互聯(lián)
網(wǎng)站路徑:http://www.muchs.cn/article6/coigog.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導(dǎo)航企業(yè)網(wǎng)站制作、自適應(yīng)網(wǎng)站、網(wǎng)站制作、手機(jī)網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化