通用的微服務(wù)架構(gòu)遷移模式
正確實(shí)施微服務(wù)架構(gòu)相較于單體應(yīng)用具有許多優(yōu)勢。很多組織都希望將他們的單體應(yīng)用代碼遷移到微服務(wù)架構(gòu)。然而,遷移到微服務(wù)并非易事,因此我們需要認(rèn)真思考是否真的需要微服務(wù)。許多單體應(yīng)用存在的問題可以通過模塊化的單體架構(gòu)輕松解決。一旦確定確實(shí)需要微服務(wù),就需要制定一套轉(zhuǎn)換單體應(yīng)用為微服務(wù)的計(jì)劃。本文將介紹一些模式,以幫助您創(chuàng)建所需的計(jì)劃。
在深入討論這些拆分單體的模式之前,我們必須先強(qiáng)調(diào)不應(yīng)該采取的做法。
不要做大爆炸重寫
在軟件開發(fā)領(lǐng)域,"大爆炸重寫"是一種術(shù)語,指的是將原本作為單一實(shí)體的應(yīng)用程序代碼,拆分并重構(gòu)成一系列微服務(wù),然后一次性將它們部署到生產(chǎn)環(huán)境的過程。正如Martin Fowler所言,大爆炸重寫通常只能確保一件事 - 風(fēng)險(xiǎn)。
大爆炸重寫是一項(xiàng)具有潛在風(fēng)險(xiǎn)的任務(wù)。它需要耗費(fèi)大量的開發(fā)時(shí)間,因?yàn)楸仨氈匦戮帉懺袉误w應(yīng)用程序的各個(gè)組成部分,將其轉(zhuǎn)化為微服務(wù)。此外,在進(jìn)行微服務(wù)架構(gòu)的開發(fā)過程中,必須凍結(jié)對原單體應(yīng)用的新開發(fā)工作,因?yàn)閱误w應(yīng)用的任何更改都必須同時(shí)在微服務(wù)中進(jìn)行。對于許多公司來說,凍結(jié)應(yīng)用程序開發(fā)工作可能帶來潛在風(fēng)險(xiǎn),因?yàn)樗麄冃枰鶕?jù)業(yè)務(wù)環(huán)境的變化隨時(shí)對軟件進(jìn)行調(diào)整。
漸進(jìn)式轉(zhuǎn)變相對較安全。它允許我們在開發(fā)過程中逐漸重構(gòu)和遷移單體應(yīng)用的不同部分,而不需要完全停止單體應(yīng)用的開發(fā)工作。這樣可以減少風(fēng)險(xiǎn),并且能夠根據(jù)業(yè)務(wù)需求靈活調(diào)整軟件。
以下是一些可用的設(shè)計(jì)模式,可以幫助組織逐步從單體架構(gòu)向微服務(wù)架構(gòu)轉(zhuǎn)變:
關(guān)于微服務(wù)相關(guān)知識(shí)與實(shí)踐技巧,推薦了解微服務(wù)及高并發(fā)、高可用架構(gòu)設(shè)計(jì)與最佳實(shí)踐課程,詳情可以咨詢中培IT學(xué)院

扼殺者模式是由著名軟件工程師Martin Fowler提出的一種設(shè)計(jì)模式,靈感源自于自然界的無花果。無花果以其獨(dú)特的方式生長,它從寄生的樹冠分枝開始發(fā)展,根慢慢延伸至地面。這些根逐漸生長并最終觸及地面,甚至在這個(gè)過程中會(huì)逐漸消亡寄主樹。在軟件世界中,我們可以借用這一生態(tài)啟示,以扼殺者模式的方式構(gòu)建微服務(wù)架構(gòu)。
在扼殺者模式中,我們以現(xiàn)有單體應(yīng)用程序?yàn)榛A(chǔ),逐步在其邊緣創(chuàng)建新的服務(wù)。這里,“邊緣”指的是現(xiàn)有單體系統(tǒng)的外圍功能或模塊。讓我們通過一個(gè)具體的例子來深入了解這個(gè)概念。

當(dāng)前單體應(yīng)用程序結(jié)構(gòu)(圖 1)
在圖 1 中,我們可以看到單體應(yīng)用程序的結(jié)構(gòu)。產(chǎn)品庫存、訂單管理和計(jì)費(fèi)管理模塊位于應(yīng)用程序的邊緣,而通知管理接收多個(gè)來自應(yīng)用程序內(nèi)的入站調(diào)用。由于入站調(diào)用來源多樣,我們無法將它們都直接重定向到通知管理。因此,我們需要另一種模式來將通知管理遷移到微服務(wù),這將在稍后討論。
現(xiàn)在,假設(shè)我們想將訂單管理模塊遷移到微服務(wù)架構(gòu)。我們可以按照以下步驟進(jìn)行操作:
步驟 1: 插入代理
部署 HTTP 代理:首先,我們需要引入一個(gè) HTTP 代理,除非您已經(jīng)擁有一個(gè)。這個(gè)代理將用于將所有調(diào)用直接重定向到單體應(yīng)用程序。引入 HTTP 代理后,您還可以監(jiān)測網(wǎng)絡(luò)上是否存在可能影響 API 調(diào)用性能的延遲。如果延遲問題嚴(yán)重,您可能需要在繼續(xù)遷移之前先解決網(wǎng)絡(luò)問題。
步驟 2: 部署微服務(wù)
部署微服務(wù):在第二步中,您將在生產(chǎn)環(huán)境中部署訂單管理微服務(wù)。請注意,在此階段,微服務(wù)不會(huì)處理任何實(shí)時(shí)流量,僅用于測試微服務(wù)的正常運(yùn)行。
步驟 3: 重定向流量
重定向流量:在第三步,我們將實(shí)際流量從 HTTP 代理重定向到新部署的訂單管理微服務(wù)。如果在這個(gè)階段出現(xiàn)問題,我們可以輕松更改 HTTP 代理的定向設(shè)置,以便快速回滾到單體應(yīng)用程序。
整個(gè)遷移過程如下圖所示:

遷移流程(圖 2)
抽象分支
在軟件開發(fā)中,當(dāng)需要提取一個(gè)模塊以滿足其他模塊的依賴時(shí),抽象分支模式可以派上用場。以前的示例中,假設(shè)我們要將通知管理功能轉(zhuǎn)換為微服務(wù),那么在這種情況下,使用抽象分支模式是明智之舉。下面是執(zhí)行此操作的步驟:
1.創(chuàng)建抽象:首先,需要?jiǎng)?chuàng)建一個(gè)抽象,它是要替換的模塊的代表。這個(gè)抽象應(yīng)該提供相同的接口和功能,以便舊代碼可以無縫地切換到新的實(shí)現(xiàn)上。
2.更改現(xiàn)有功能的客戶端:接下來,必須對舊代碼進(jìn)行重構(gòu),以便它使用在步驟1中創(chuàng)建的抽象。這意味著修改依賴這個(gè)模塊的代碼,以便它們與新抽象進(jìn)行交互。
3.創(chuàng)建新的實(shí)現(xiàn):然后,需要為功能創(chuàng)建一個(gè)全新的微服務(wù)實(shí)現(xiàn)。這個(gè)新實(shí)現(xiàn)應(yīng)該基于抽象接口,同時(shí)還需要進(jìn)行充分的測試以確保其功能正確性。
4.切換實(shí)現(xiàn):在完成足夠多的測試并獲得信心后,可以切換到新的代碼實(shí)現(xiàn)上。這通常意味著將新的微服務(wù)部署到生產(chǎn)環(huán)境,并確保它可以勝任原有功能。
5.清理:一旦新的微服務(wù)已經(jīng)啟動(dòng)并在生產(chǎn)環(huán)境中運(yùn)行,建議清理舊的代碼庫和刪除舊的模塊。如果抽象不再需要,也可以考慮將其刪除。然而,在很多情況下,保留抽象是有益的,因?yàn)樗梢蕴岣叽a庫的質(zhì)量和可維護(hù)性。
為了更好地理解整個(gè)過程,請參考下圖。

抽象分支(圖3)
抽象分支模式可以在許多場景中使用。我們建議盡可能使用"Strangler Fig"模式,而不是抽象分支。如果你確定無法使用"Strangler Fig"模式將單體應(yīng)用的某些部分替換為微服務(wù),那么你可以考慮使用抽象分支。
并行運(yùn)行
無論你經(jīng)過多少次測試,錯(cuò)誤的可能性仍然存在。當(dāng)你遷移關(guān)鍵系統(tǒng)時(shí),運(yùn)氣不能成為你唯一依賴的因素。在這種情況下,并行運(yùn)行模式可以提供幫助。在這一模式下,我們會(huì)在生產(chǎn)環(huán)境同時(shí)部署新開發(fā)的微服務(wù)和舊的單體應(yīng)用。數(shù)據(jù)將流經(jīng)這兩個(gè)系統(tǒng)。一開始,單體應(yīng)用將是唯一的數(shù)據(jù)來源。我們將比較新微服務(wù)的輸出與單體應(yīng)用的結(jié)果,如果發(fā)現(xiàn)不匹配,就會(huì)在微服務(wù)中修復(fù)問題。隨著時(shí)間的推移,當(dāng)我們對新的微服務(wù)系統(tǒng)充滿信心時(shí),可以停用單體應(yīng)用的相關(guān)功能,使微服務(wù)成為唯一的數(shù)據(jù)源。
舉個(gè)例子,假設(shè)我們想將計(jì)費(fèi)管理從單體應(yīng)用遷移到微服務(wù)。在這種模式下,我們會(huì)開發(fā)一個(gè)新的微服務(wù),并將相同的流量引導(dǎo)到新的微服務(wù)上。每天結(jié)束時(shí),我們可以使用批處理作業(yè)來比較舊系統(tǒng)和新系統(tǒng)生成的賬單是否相同。一旦我們對新系統(tǒng)有足夠的信心,就可以停用單體應(yīng)用中的計(jì)費(fèi)管理功能。此外,還有一些開源庫,如GitHub的Scientist庫,可以幫助你更好地實(shí)現(xiàn)這種模式。

并行運(yùn)行模式(圖 4)
這種模式特別適用于將功能從單體應(yīng)用中遷移到微服務(wù)時(shí)。例如,如果你需要添加新功能,比如在每次成功交易后向用戶發(fā)送電子郵件折扣券,只需在單體應(yīng)用的訂單模塊中添加新代碼以調(diào)用新的折扣微服務(wù)即可。但如果你沒有可用的代碼呢?如果你正在使用其他供應(yīng)商的解決方案或某些SaaS服務(wù),也可以實(shí)現(xiàn)這一目標(biāo)。接下來的兩種模式專門針對這種情況進(jìn)行了定制。
裝飾協(xié)作者(Decorating Collaborator)
這種模式的靈感源自于我們熟悉且喜愛的裝飾者模式。與裝飾者模式類似,這里我們需要引入一個(gè)代理。我們讓調(diào)用通過代理傳遞到單體應(yīng)用,然后根據(jù)單體應(yīng)用的響應(yīng),代理將調(diào)用我們新創(chuàng)建的微服務(wù)。

裝飾協(xié)作者(圖5)
圖 5展示了裝飾協(xié)作者模式的機(jī)制。這種模式僅在所有微服務(wù)所需的數(shù)據(jù)都已存在于請求或響應(yīng)中時(shí)才應(yīng)該使用。如果數(shù)據(jù)不存在,那么我們新創(chuàng)建的微服務(wù)必須連接到單體數(shù)據(jù)庫上。換句話說,我們的新微服務(wù)需要與單體數(shù)據(jù)庫耦合,這顯然不是一個(gè)好主意。
更改數(shù)據(jù)捕獲模式
在這種方案中,我們將實(shí)時(shí)響應(yīng)數(shù)據(jù)庫的更改。舉個(gè)例子,假設(shè)我們希望為系統(tǒng)中新創(chuàng)建的每個(gè)客戶生成一張會(huì)員卡。為了實(shí)現(xiàn)這一目標(biāo),我們可以監(jiān)測客戶表的變動(dòng)。一旦檢測到有新客戶記錄被插入客戶表中,我們就可以調(diào)用Loyalty微服務(wù)。該微服務(wù)負(fù)責(zé)發(fā)放會(huì)員卡并向客戶發(fā)送包含詳細(xì)信息的電子郵件。為了監(jiān)聽數(shù)據(jù)庫的變化,我們可以采用多種方法。其中一種方式是使用觸發(fā)器,通過在客戶表上設(shè)置觸發(fā)器來捕獲插入事件。另一種方式是利用數(shù)據(jù)庫的事務(wù)日志,通過讀取日志文件來獲取最新的更改信息。此外,我們還可以編寫一個(gè)定期觸發(fā)的流程,用來檢查數(shù)據(jù)庫中發(fā)生的更改,并及時(shí)做出相應(yīng)的處理。
結(jié)語
正確實(shí)施微服務(wù)架構(gòu)可帶來許多優(yōu)勢。將單體應(yīng)用程序轉(zhuǎn)變?yōu)槲⒎?wù)并非一蹴而就的過程。我們需要意識(shí)到,這是一項(xiàng)漫長的馬拉松,而非一場短時(shí)競賽。成功完成這個(gè)轉(zhuǎn)變需要耐心,并且必須做出明智的架構(gòu)決策。
本文我們探討了一些可供選擇的模式。通常情況下,需要應(yīng)用多種模式才能完全將單體應(yīng)用程序轉(zhuǎn)換為微服務(wù)。最后,我強(qiáng)烈建議在遷移到微服務(wù)之前花時(shí)間深入了解你計(jì)劃使用的策略。這樣的準(zhǔn)備工作終將會(huì)帶來回報(bào)。推薦各位軟件設(shè)計(jì)師和技術(shù)人員了解中培IT學(xué)院微服務(wù)及高并發(fā)、高可用架構(gòu)設(shè)計(jì)與最佳實(shí)踐課程,本課程涵蓋微服務(wù)架構(gòu)設(shè)計(jì)方法、單體應(yīng)用向微服務(wù)架構(gòu)遷移的實(shí)踐經(jīng)驗(yàn)、微服務(wù)架構(gòu)相關(guān)的解決方案、微服務(wù)治理相關(guān)技術(shù)等內(nèi)容,通過學(xué)習(xí)本課程,將促進(jìn)從業(yè)者、企業(yè)在微服務(wù)領(lǐng)域的發(fā)展產(chǎn)生深遠(yuǎn)影響。
關(guān)于技能提升等相關(guān)內(nèi)容,歡迎聯(lián)系中培IT學(xué)院
