摘要:相反,它由單體中的適配器和使用一個或多個進程間通信機制的服務(wù)組成。因為微服務(wù)架構(gòu)的本質(zhì)是一組圍繞業(yè)務(wù)功能組織的松耦合服務(wù)。如果你嘗試將此類功能實現(xiàn)為服務(wù),則通常會發(fā)現(xiàn),由于過多的進程間通信而導(dǎo)致性能下降。這是快速展示微服務(wù)架構(gòu)價值的好方法。
你很有可能正在處理大型復(fù)雜的單體應(yīng)用程序,每天開發(fā)和部署應(yīng)用程序的經(jīng)歷都很緩慢而且很痛苦。微服務(wù)看起來非常適合你的應(yīng)用程序,但它也更像是一項遙不可及的必殺技。如何才能走上微服務(wù)架構(gòu)的道路?下面將介紹一些策略,幫你擺脫單體地獄,而無須從頭開始重寫你的應(yīng)用程序。
通過開發(fā)所謂的絞殺者應(yīng)用程序(strangler application),可以逐步將單體架構(gòu)轉(zhuǎn)換為微服務(wù)架構(gòu)。絞殺者應(yīng)用程序的想法來自絞殺式藤蔓,這些藤蔓在雨林中生長,它們包圍繞樹木生成,甚至有時會殺死樹木。絞殺者應(yīng)用程序是一個由微服務(wù)組成的新應(yīng)用程序,通過將新功能作為服務(wù),并逐步從單體應(yīng)用程序中提取服務(wù)來實現(xiàn)。隨著時間的推移,當(dāng)絞殺者應(yīng)用程序?qū)崿F(xiàn)越來越多的功能時,它會縮小并最終消滅單體應(yīng)用程序。開發(fā)絞殺者應(yīng)用程序的一個重要好處是,與宇宙大爆炸式的徹底重寫不同,它可以立刻落地,更快為企業(yè)提供價值。
有三種主要策略可以實現(xiàn)對單體的“絞殺”,并逐步用微服務(wù)替換之:
1) 將新功能實現(xiàn)為服務(wù)。 2)隔隔表現(xiàn)層和后端。 3) 通過將功能提取到服務(wù)中來分解單體。
第一種策略阻止了單體的發(fā)展。它通常是一種快速展示微服務(wù)價值的方法,有助于讓遷移和重構(gòu)的工作獲得公司內(nèi)部各個層面支持。另外兩種策略打破了單體。在重構(gòu)單體時,你有時可能會使用第二種策略,但你肯定會使用第三種策略,因為它能實現(xiàn)將功能從單體遷移到絞殺者應(yīng)用程序中。
下面讓我們來看一看這些策略。
1.將新功能實現(xiàn)為服務(wù)“挖坑法則”(The Law of Holes)指出:如果你發(fā)現(xiàn)自己已經(jīng)陷入了困境,就不要再給自己繼續(xù)挖坑了。當(dāng)你的單體應(yīng)用變得無法管理時,這是一個很好的可供參考的建議。換句話說,如果你有一個龐大的、復(fù)雜的單體應(yīng)用程序,請不要通過向單體添加代碼來實現(xiàn)新功能。這將使你的單體變得更龐大,更難以管理。相反,你應(yīng)該將新功能實現(xiàn)為服務(wù)。
這是開始將單體應(yīng)用程序遷移到微服務(wù)架構(gòu)的好方法。它降低了單體的生長速度,加速了新功能的開發(fā)(因為是在全新的代碼庫中進行開發(fā)),還能快速展示采用微服務(wù)架構(gòu)的價值。
把新的服務(wù)與單體集成圖 1顯示了將新功能實現(xiàn)為服務(wù)后的應(yīng)用程序架構(gòu)。除了新服務(wù)和單體外,該架構(gòu)還包括另外兩個將服務(wù)集成到應(yīng)用程序中的元素:
■ API Gateway:將對新功能的請求路由到新服務(wù),并將遺留請求路由到單體。
■ 集成膠水代碼:將服務(wù)與單體結(jié)合。它使服務(wù)能夠訪問單體所擁有的數(shù)據(jù),并能夠調(diào)用單體實現(xiàn)的功能。
集成膠水的代碼不是一個獨立組件。相反,它由單體中的適配器和使用一個或多個進程間通信機制的服務(wù)組成。
何時把新功能實現(xiàn)為服務(wù)理想情況下,你應(yīng)該在絞殺者應(yīng)用程序中而不是在單體中實現(xiàn)每個新功能。你將實現(xiàn)新功能作為新服務(wù)或作為現(xiàn)有服務(wù)的一部分。這樣你就可以避免和單體代碼庫打交道。不幸的是,并非每個新功能都可以作為服務(wù)實現(xiàn)。
因為微服務(wù)架構(gòu)的本質(zhì)是一組圍繞業(yè)務(wù)功能組織的松耦合服務(wù)。例如,某個功能可能太小而無法成為有意義的服務(wù)。例如,你可能只需要向現(xiàn)有類添加一些字段和方法。或者新功能可能與單體中的代碼緊耦合。如果你嘗試將此類功能實現(xiàn)為服務(wù),則通常會發(fā)現(xiàn),由于過多的進程間通信而導(dǎo)致性能下降。你可能還會遇到數(shù)據(jù)一致性的問題。如果新功能無法作為服務(wù)實現(xiàn),則解決方案通常是首先在單體中實現(xiàn)新功能。之后,你可以將該功能以及其他相關(guān)功能提取到自己的服務(wù)中。
以服務(wù)的方式實現(xiàn)新功能,可以加速這些功能的開發(fā)。這是快速展示微服務(wù)架構(gòu)價值的好方法。它還能夠降低單體的增長速度。但最終,你需要使用另外兩種策略來分解單體。你需要通過將單體中的功能提取到服務(wù),從而將單體中的功能遷移到絞殺者應(yīng)用程序。你也可以通過水平分割單體架構(gòu)來提高開發(fā)速度。我們來看看如何做到這一點。
2.隔離表現(xiàn)層與后端縮小單體應(yīng)用程序的一個策略是將表現(xiàn)層與業(yè)務(wù)邏輯和數(shù)據(jù)訪問層分開。典型的企業(yè)應(yīng)用程序包含以下各層:
■ 表現(xiàn)邏輯層:它由處理 HTTP 請求的模塊組成,并生成實現(xiàn) Web UI 的 HTML 頁面。在具有復(fù)雜用戶界面的應(yīng)用程序中,表現(xiàn)層通常包含大量代碼。
■ 業(yè)務(wù)邏輯層:由實現(xiàn)業(yè)務(wù)規(guī)則的模塊組成,這些模塊在企業(yè)應(yīng)用程序中可能很復(fù)雜。
■ 數(shù)據(jù)訪問邏輯層:包含訪問基礎(chǔ)設(shè)施服務(wù)(如數(shù)據(jù)庫和消息代理)的模塊。 表現(xiàn)邏輯層與業(yè)務(wù)和數(shù)據(jù)訪問邏輯層之間通常存在清晰的邊界。業(yè)務(wù)層具有粗粒度 API,由一個或多個封裝業(yè)務(wù)邏輯的門面(Facade)組成。這個 API 是一個自然的接縫,你可以沿著它將單體分成兩個較小的應(yīng)用程序,如圖 2 所示。
一個應(yīng)用程序包含表現(xiàn)層,另一個包含業(yè)務(wù)和數(shù)據(jù)訪問邏輯層。分割后,表現(xiàn)邏輯應(yīng)用程序?qū)I(yè)務(wù)邏輯應(yīng)用程序進行遠程調(diào)用。
以這種方式拆分單體應(yīng)用有兩個主要好處。它使你能夠彼此獨立地開發(fā)、部署和擴展這兩個應(yīng)用程序。特別是,它允許表現(xiàn)層開發(fā)人員快速迭代用戶界面并輕松執(zhí)行A/B測試,而無須部署后端。這種方法的另一個好處是它公開了業(yè)務(wù)邏輯的一組遠程API,可以被稍后開發(fā)的微服務(wù)調(diào)用。
但這種策略只是部分解決方案。很可能至少有一個或兩個最終的應(yīng)用程序仍然是一個難以管理的單體。你需要使用第三種策略將單體替換為服務(wù)。
3.提取業(yè)務(wù)能力到服務(wù)中將新功能實現(xiàn)為服務(wù),并從后端拆分出前端Web應(yīng)用程序并不會讓你抵達勝利的彼岸。你仍將最終在單體代碼中進行大量開發(fā)。如果你希望顯著改進應(yīng)用程序的架構(gòu)并提高開發(fā)速度,則需要通過逐步將業(yè)務(wù)功能從單體遷移到服務(wù)來拆分單體應(yīng)用。當(dāng)你使用此策略時,隨著時間推移,服務(wù)實現(xiàn)的業(yè)務(wù)功能數(shù)量會增加,而單體會逐漸縮小。
你想要提取到服務(wù)中的功能是對單體應(yīng)用自上而下的一個“垂直切片”。該切片包含以下內(nèi)容:
■ 實現(xiàn)API端點的入站適配器。 ■ 領(lǐng)域邏輯。 ■ 出站適配器,例如數(shù)據(jù)庫訪問邏輯。 ■ 單體的數(shù)據(jù)庫模式。
如圖 3 所示,此代碼從單體中提取并移至獨立服務(wù)中。API Gateway 將調(diào)用提取的業(yè)務(wù)功能的請求路由到該服務(wù),并將其他請求路由到單體。單體和服務(wù)通過集成膠水代碼進行協(xié)作。集成膠水由服務(wù)中的適配器和使用一個或多個進程間通信機制的單體組成。
提取服務(wù)具有挑戰(zhàn)性。你需要確定如何將單體的領(lǐng)域模型分成兩個獨立的領(lǐng)域模型,其中一個模型成為服務(wù)的領(lǐng)域模型。你需要打破對象引用等依賴。你甚至可能需要拆分類,以將功能移動到服務(wù)中。對了,你還需要重構(gòu)數(shù)據(jù)庫。
提取服務(wù)通常很耗時,尤其是當(dāng)單體的代碼庫很混亂時。因此,你需要仔細考慮要提取的服務(wù)。應(yīng)當(dāng)重點關(guān)注重構(gòu)那些能夠提供很多價值的應(yīng)用程序部分。在提取服務(wù)之前,問問自己這樣做的好處是什么。
例如,提取一項實現(xiàn)對業(yè)務(wù)至關(guān)重要且不斷發(fā)展的功能的服務(wù)是值得的。如果沒有太多的好處,那么在提取服務(wù)方面投入精力是沒有價值的。在本節(jié)的后面部分,我將介紹一些用于確定服務(wù)提取范圍和時間的策略。但首先讓我們更詳細地了解一下在提取服務(wù)時將面臨的一些挑戰(zhàn)以及解決這些挑戰(zhàn)的方法。
提取服務(wù)時會遇到以下這些挑戰(zhàn):
■ 拆解領(lǐng)域模型。 ■ 重構(gòu)數(shù)據(jù)庫。
拆解領(lǐng)域模型為了提取服務(wù),你需要從單體的領(lǐng)域模型中提取服務(wù)相關(guān)的領(lǐng)域模型。你需要進行大動作來拆分領(lǐng)域模型。你將遇到的一個挑戰(zhàn)是消除跨越服務(wù)邊界的對象引用。保留在單體中的類可能會引用已移動到服務(wù)的類,反之亦然。例如,想象一下,如圖 4 所示,你提取了Order Service,其Order類引用了單體的Restaurant類。因為服務(wù)實例通常是一個進程,所以讓對象引用跨越服務(wù)邊界是沒有意義的。你需要消除這種類型的對象引用。
解決此問題的一個好方法是根據(jù)DDD聚合進行思考。聚合使用主鍵而不是對象引用相互引用。因此,你可以將 Order 和 Restaurant 類視為聚合,如圖5所示,將Order類中對 Restaurant 的引用替換為存儲主鍵值的restaurantId 字段。
使用主鍵替換對象引用的一個問題是,雖然這是對類的一個小改動,但它可能會對期望對象引用的類的客戶端產(chǎn)生很大的影響。在本節(jié)的后面部分,我將介紹如何通過在服務(wù)和單體之間復(fù)制數(shù)據(jù)來減少更改的范圍。例如,Delivery Service可以定義一個Restaurant類,后者是單體中Restaurant 類的復(fù)制品。
提取服務(wù)通常比將整個類移動到服務(wù)中的工作量要大得多。拆分領(lǐng)域模型面臨的更大挑戰(zhàn)是提取嵌入在具有其他職責(zé)的類中的功能。這個問題經(jīng)常出現(xiàn)在具有過多職責(zé)的上帝類(God Class)中。例如,Order 類是FTGO應(yīng)用程序中的上帝類之一。它實現(xiàn)了多種業(yè)務(wù)功能,包括訂單管理、送餐管理等。Delivery 實體會實現(xiàn)之前與Order類中的其他功能捆綁在一起的送餐管理功能。
重構(gòu)數(shù)據(jù)庫拆分領(lǐng)域模型不僅僅涉及更改代碼。領(lǐng)域模型中的許多類都是在數(shù)據(jù)庫中持久化保存的。它們的字段映射到具體的數(shù)據(jù)庫模式。因此,當(dāng)你從單體中提取服務(wù)時,你也會移動數(shù)據(jù)。你需要將表從單體的數(shù)據(jù)庫移動到服務(wù)的數(shù)據(jù)庫。
此外,拆分實體時,需要拆分相應(yīng)的數(shù)據(jù)庫表并將新表移動到服務(wù)中。例如,在將送餐管理提取到服務(wù)中時,你需要拆分Order實體并提取出一個Delivery實體。在數(shù)據(jù)庫級別,你要拆分ORDERS表并定義新的DELIVERY表。然后,將DELIVERY表移動到該服務(wù)。
復(fù)制數(shù)據(jù)以避免更廣泛的更改如上所述,提取服務(wù)需要你對單體的領(lǐng)域模型做出更改。例如,使用主鍵和拆分類替換對象引用。這些類型的更改可能會影響代碼庫,并要求你對單體各個受影響的部分進行廣泛的更改。例如,如果拆分Order實體并提取Delivery實體,則必須更改代碼中引用被移動字段而受影響的每個部分。進行這些改變可能會非常耗時,并且可能成為打破單體的巨大障礙。
延遲并可能避免進行這些昂貴更改的一種好方法是使用類似于《數(shù)據(jù)庫重構(gòu)》一書中描述的方法。重構(gòu)數(shù)據(jù)庫的一個主要障礙是更改該數(shù)據(jù)庫的所有客戶端以使用新模式。本書中提出的解決方案是在過渡期內(nèi)保留原模式,并使用觸發(fā)器在原模式和新模式間同步。然后,你可以將客戶端從舊模式遷移到新模式。
從單體中提取服務(wù)時,我們可以使用類似的方法。例如,在提取Delivery實體時,我們將Order實體在過渡期內(nèi)大部分保持不變。如圖6所示,我們將與交付相關(guān)的字段設(shè)置為只讀,并通過將數(shù)據(jù)從Delivery Service復(fù)制回單體來使其保持最新。因此,我們只需要在單體的代碼中找到更新這些字段的位置,并更改它們?yōu)檎{(diào)用新的Delivery Service即可。
通過從Delivery Service復(fù)制數(shù)據(jù)來保留Order實體的結(jié)構(gòu),可以顯著減少我們需要立即完成的工作量。隨著時間的推移,我們可以將使用與交付相關(guān)的Order實體字段或ORDERS表列的代碼遷移到Delivery Service。更重要的是,我們可能永遠不需要在單體中做出改變。如果隨后將該代碼提取到服務(wù)中,則該服務(wù)可以訪問DeliveryService。
確定提取何種服務(wù)以及何時提取正如我所提到的,拆解單體是耗時的。它分散了實施新功能的人力資源。因此,你必須仔細確定提取服務(wù)的順序。你需要專注于提取能夠帶來最大收益的服務(wù)。更重要的是,你希望不斷向業(yè)務(wù)部門展示遷移到微服務(wù)架構(gòu)的價值。
在任何旅程中,了解你要去的地方至關(guān)重要。開始遷移到微服務(wù)的好方法是使用時間框架來定義工作。你應(yīng)該花費很短的時間,例如幾周,集思廣益討論理想架構(gòu)并定義一組服務(wù)。這將為你提供一個目標(biāo)。但是,重要的是要記住,這種架構(gòu)并非一成不變。當(dāng)你分解單體并獲得經(jīng)驗后,你應(yīng)該應(yīng)用你所獲得的經(jīng)驗對重構(gòu)計劃及時做出調(diào)整。
一旦確定了目標(biāo),下一步就是開始拆分單體結(jié)構(gòu)。可以使用幾種不同的策略來確定提取服務(wù)的順序。
一種策略是有效地凍結(jié)單體架構(gòu)的開發(fā)并按需提取服務(wù)。你可以提取必要的服務(wù)并進行更改,而不是在單體中實現(xiàn)功能或修復(fù)錯誤。這種方法的一個好處是它會迫使你打破單體。一個弊端是服務(wù)的提取是由短期需求而不是長期需求驅(qū)動的。例如,即使你對系統(tǒng)中相對穩(wěn)定的部分進行了少量更改,也需要你提取服務(wù)。因此,你做的大量工作可能只能換來較小的收益。
另一種策略是更有計劃的方法,你可以根據(jù)提取應(yīng)用程序模塊獲得的預(yù)期收益,對應(yīng)用程序的模塊進行排名。提取服務(wù)有益的原因有以下幾點:
■ 加速開發(fā):如果你的應(yīng)用程序的路線圖表明應(yīng)用程序的特定部分將在明年進行大量開發(fā),那么將其轉(zhuǎn)換為服務(wù)可加速開發(fā)。
■ 解決性能、可擴展性或可靠性問題:如果應(yīng)用程序的特定部分存在性能、可擴展性問題或不可靠,那么將其轉(zhuǎn)換為服務(wù)是有價值的。
■ 允許提取其他一些服務(wù):由于模塊之間的依賴關(guān)系,有時提取一個服務(wù)會簡化另一個服務(wù)的提取。 你可以使用這些條件將重構(gòu)任務(wù)添加到應(yīng)用程序的“待辦事項”中,并按預(yù)期收益排名。這種方法的好處在于它更具戰(zhàn)略性,并且更符合業(yè)務(wù)需求。在做 Sprint 的計劃時,你可以確定實現(xiàn)功能或提取服務(wù)哪個更有價值。
本文摘自《微服務(wù)架構(gòu)設(shè)計模式》,經(jīng)出版方授權(quán)發(fā)布。延伸閱讀:
作者::[美]?克里斯·理查森(Chris Richardson)?著 譯者:喻勇?譯
推薦語:
微服務(wù)架構(gòu)的先驅(qū)、Java 開發(fā)者社區(qū)的意見領(lǐng)袖 Chris Richardson親筆撰寫,微服務(wù)實用落地指南 。
涵蓋44個架構(gòu)設(shè)計模式,系統(tǒng)解決服務(wù)拆分、事務(wù)管理、查詢和跨服務(wù)通信等難題易寶支付CTO陳斌、PolarisTech 聯(lián)合創(chuàng)始人蔡書、才云科技CEO張鑫等多位專家鼎力推薦。
贈送三本《微服務(wù)架構(gòu)設(shè)計模式》給大家這么好的書必須要買來學(xué)習(xí)啊,25號我這邊有一些優(yōu)惠卷到時候通過文章發(fā)布出來,大家可以用優(yōu)惠卷進行購買,很劃算的。
同時也搶先給大家送3本,識別下方二維碼,對話窗口回復(fù) 架構(gòu) 獲取抽獎二維碼參與抽獎。結(jié)束時間為27號早晨8點。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/6859.html
摘要:在將您的單體應(yīng)用微服務(wù)化時,也可以采用這種方式,即新的功能使用微服務(wù)架構(gòu)來開發(fā),通過對原有的單體應(yīng)用暴露和端口號的方式供其進行調(diào)用和使用。如果這時其他服務(wù)再來訪問這個和端口號,那一定會出現(xiàn)找不到服務(wù)等各種故障。 作者注:聯(lián)系方式 leontian1024@gmail.com || github.com/XinyaoTian新人入行,非常期待能與各位大牛們討論,感謝各位的閱讀,希望對您有...
摘要:在將您的單體應(yīng)用微服務(wù)化時,也可以采用這種方式,即新的功能使用微服務(wù)架構(gòu)來開發(fā),通過對原有的單體應(yīng)用暴露和端口號的方式供其進行調(diào)用和使用。如果這時其他服務(wù)再來訪問這個和端口號,那一定會出現(xiàn)找不到服務(wù)等各種故障。 作者注:聯(lián)系方式 leontian1024@gmail.com || github.com/XinyaoTian新人入行,非常期待能與各位大牛們討論,感謝各位的閱讀,希望對您有...
摘要:有問題可通過微博聯(lián)系我開源項目微信小程序微信小應(yīng)用資源破解文檔微信小應(yīng)用示例代碼文檔簡易教程開發(fā)者工具文檔文檔視圖組件文檔常見問題教程微信小程序開發(fā)文檔微信公眾平臺文檔微信小程序怎么開發(fā)玩物志用一個上午上線了電商應(yīng)用愛范兒 有問題可通過微博聯(lián)系我: http://weibo.com/jinfali 開源項目 wechatApp-demo - 微信小程序 DEMO weapp-ide-...
摘要:有問題可通過微博聯(lián)系我開源項目微信小程序微信小應(yīng)用資源破解文檔微信小應(yīng)用示例代碼文檔簡易教程開發(fā)者工具文檔文檔視圖組件文檔常見問題教程微信小程序開發(fā)文檔微信公眾平臺文檔微信小程序怎么開發(fā)玩物志用一個上午上線了電商應(yīng)用愛范兒 有問題可通過微博聯(lián)系我: http://weibo.com/jinfali 開源項目 wechatApp-demo - 微信小程序 DEMO weapp-ide-...
閱讀 812·2021-11-18 10:02
閱讀 2503·2021-11-11 16:54
閱讀 2750·2021-09-02 09:45
閱讀 654·2019-08-30 12:52
閱讀 2774·2019-08-29 14:04
閱讀 2745·2019-08-29 12:39
閱讀 447·2019-08-29 12:27
閱讀 1887·2019-08-26 13:23