譯者 | 劉汪洋
審校 | 重樓
當(dāng)單體架構(gòu)成為項(xiàng)目增長(zhǎng)的瓶頸時(shí),遷移到微服務(wù)架構(gòu)就成了必然的選擇。
微服務(wù)雖然具有明顯的優(yōu)點(diǎn),但由于其內(nèi)在復(fù)雜性和缺乏一種通用的遷移方案,實(shí)施過程中可能會(huì)遇到不少挑戰(zhàn)。本文旨在分享解決方案架構(gòu)師在單體架構(gòu)向微服務(wù)遷移過程中的專業(yè)經(jīng)驗(yàn),并闡述如何在確保項(xiàng)目安全性和可靠性的前提下,成功完成遷移。
單體架構(gòu)到微服務(wù):遷移路線圖
下面,我們將從涉及的五個(gè)主要步驟入手,深入探討如何讓單體架構(gòu)向微服務(wù)的遷移過程更為順利。
第一步:技術(shù)與商業(yè)需求分析
成功地從單體架構(gòu)遷移到微服務(wù)的第一步是從商業(yè)角度證實(shí)這一轉(zhuǎn)型的必要性。每個(gè)項(xiàng)目都有其特定的技術(shù)優(yōu)勢(shì)和局限性,因此,這一轉(zhuǎn)型將對(duì)整個(gè)產(chǎn)品架構(gòu)產(chǎn)生深遠(yuǎn)影響。這個(gè)新架構(gòu)需要能夠適應(yīng)未來的業(yè)務(wù)增長(zhǎng)。因此,建議與商業(yè)分析師和技術(shù)專家聯(lián)手,準(zhǔn)確地評(píng)估當(dāng)前系統(tǒng)的需求,并制定一個(gè)高效的開發(fā)路線圖。
盡管微服務(wù)多年來一直是業(yè)界熱點(diǎn),但并不是所有項(xiàng)目都適合采用微服務(wù)。事實(shí)上,完全符合微服務(wù)理念的項(xiàng)目是相當(dāng)罕見的。盡管微服務(wù)已經(jīng)成為一種行業(yè)趨勢(shì),但至今還沒有一個(gè)完美的微服務(wù)實(shí)施案例。但這不應(yīng)成為企業(yè)進(jìn)行轉(zhuǎn)型的障礙。關(guān)鍵在于合理地設(shè)定期望,并仔細(xì)評(píng)估預(yù)期的技術(shù)方案是否能夠?qū)崿F(xiàn)既定目標(biāo)。
應(yīng)用現(xiàn)代化策略中,將現(xiàn)有應(yīng)用遷移到微服務(wù)是一種常見的做法。然而,從零開始就使用微服務(wù)構(gòu)建應(yīng)用并不總是最佳選擇。相反,應(yīng)首先考慮采用單體架構(gòu),或者至少在其中實(shí)現(xiàn)核心業(yè)務(wù)邏輯。這樣,后續(xù)的服務(wù)拆分會(huì)更為簡(jiǎn)單。過度追求微服務(wù)之間的隔離可能會(huì)導(dǎo)致不必要的復(fù)雜性。
對(duì)于大型團(tuán)隊(duì)參與的項(xiàng)目,微服務(wù)無疑是一個(gè)合適的選擇。它們不僅在系統(tǒng)架構(gòu)層面提供了可擴(kuò)展性,還能在團(tuán)隊(duì)協(xié)作方面帶來便利。這種架構(gòu)的一個(gè)顯著優(yōu)勢(shì)是能夠整合多種不同的技術(shù)棧。
在正式遷移到微服務(wù)之前,進(jìn)行全面的技術(shù)審計(jì)是非常關(guān)鍵的。這一審計(jì)應(yīng)明確當(dāng)前項(xiàng)目所依賴的技術(shù)棧,并評(píng)估這些技術(shù)是否可能成為未來發(fā)展的制約因素。如果有這種可能,應(yīng)考慮是否需要采用其他更適合微服務(wù)的技術(shù)選項(xiàng)。與具有特定技術(shù)專長(zhǎng)的專家進(jìn)行咨詢,可以獲取有價(jià)值的建議,從而確保架構(gòu)轉(zhuǎn)型過程的平穩(wěn)和高效。
第二步:識(shí)別適合遷移到微服務(wù)的系統(tǒng)組件
接下來,我們需要確定哪些系統(tǒng)組件適合遷移到微服務(wù),以及這些微服務(wù)將如何進(jìn)行模塊間的交互。簡(jiǎn)而言之,這一步驟涉及到對(duì)產(chǎn)品總體架構(gòu)的設(shè)計(jì),以及確定哪些服務(wù)應(yīng)當(dāng)優(yōu)先進(jìn)行拆分。
微服務(wù)在處理某些特定功能時(shí)表現(xiàn)尤為出色,如實(shí)時(shí)通信、數(shù)據(jù)處理流程、后端任務(wù)處理,或與外部服務(wù)的接口。這些功能雖然可能需要訪問單體架構(gòu)中的數(shù)據(jù),但在技術(shù)實(shí)現(xiàn)上是相對(duì)獨(dú)立的。
第三步:?jiǎn)误w架構(gòu)到微服務(wù)的拆分策略
拆分單體架構(gòu)到微服務(wù)有兩種主要方法。
第一種方法是從單體架構(gòu)中逐步剝離特定功能,同時(shí)逐漸減少其與其他組件的依賴性。一旦完全解耦并設(shè)計(jì)了新的 API,這些功能便可以作為獨(dú)立的微服務(wù)發(fā)布。這種方法通常需要對(duì)原有的單體架構(gòu)進(jìn)行較大幅度的修改。
第二種方法則是復(fù)制所需的功能,并在保留單體架構(gòu)中原有功能的同時(shí),將其開發(fā)為一個(gè)新的微服務(wù)。一旦新的微服務(wù)經(jīng)過全面測(cè)試并確認(rèn)功能完備,便可以從單體架構(gòu)中移除原有功能。
第四步:數(shù)據(jù)管理策略
微服務(wù)架構(gòu)的一個(gè)核心原則是,每個(gè)微服務(wù)應(yīng)擁有其專屬的數(shù)據(jù)庫(kù)。然而,由于數(shù)據(jù)庫(kù)對(duì)象間可能存在交集和依賴關(guān)系,拆分單體數(shù)據(jù)庫(kù)通常是一項(xiàng)具有挑戰(zhàn)性的任務(wù)。
不同的微服務(wù)可以采用不同的數(shù)據(jù)庫(kù)、編程語(yǔ)言和數(shù)據(jù)存儲(chǔ)方案。某些數(shù)據(jù)庫(kù)可能比其他數(shù)據(jù)庫(kù)更為復(fù)雜,這使得將所有數(shù)據(jù)集中到一個(gè)統(tǒng)一數(shù)據(jù)庫(kù)中變得不現(xiàn)實(shí)。因此,針對(duì)特定類型的數(shù)據(jù),通常會(huì)使用專用的存儲(chǔ)系統(tǒng)。
在微服務(wù)的數(shù)據(jù)管理方面,可以根據(jù)涉及的數(shù)據(jù)模式進(jìn)行相應(yīng)的操作分類。
獨(dú)享數(shù)據(jù)庫(kù)模式(Database-per-Service)
在微服務(wù)架構(gòu)中,每個(gè)服務(wù)獨(dú)立數(shù)據(jù)庫(kù)模式強(qiáng)調(diào)了模塊自主性和數(shù)據(jù)封裝的重要性。該模式通過為每個(gè)微服務(wù)配置專屬數(shù)據(jù)庫(kù),確保了數(shù)據(jù)一致性和隔離性,從而降低了服務(wù)間的數(shù)據(jù)競(jìng)爭(zhēng)風(fēng)險(xiǎn)。
然而,這種做法也使得數(shù)據(jù)集成和跨服務(wù)查詢變得更為復(fù)雜,因此需要高效的通信協(xié)議和明確的接口定義。同時(shí),數(shù)據(jù)庫(kù)模式的變更需要謹(jǐn)慎處理,以防意外導(dǎo)致服務(wù)中斷。但憑借合適的策略,該模式能顯著提升微服務(wù)生態(tài)系統(tǒng)的可擴(kuò)展性和容錯(cuò)能力。
SAGA 模式
SAGA 模式是解決微服務(wù)事務(wù)中跨分布式系統(tǒng)數(shù)據(jù)一致性問題的關(guān)鍵策略。與依賴傳統(tǒng)數(shù)據(jù)庫(kù)事務(wù)不同,SAGA 模式將事務(wù)操作拆分為一系列可獨(dú)立執(zhí)行且可回滾的步驟。如果某個(gè)步驟執(zhí)行失敗,將觸發(fā)相應(yīng)的補(bǔ)償事務(wù)以保證整體數(shù)據(jù)一致性。
這種分布式處理方式雖然增強(qiáng)了系統(tǒng)的彈性和可擴(kuò)展性,但也要求精細(xì)的任務(wù)編排和錯(cuò)誤處理機(jī)制,以有效地應(yīng)對(duì)可能出現(xiàn)的失敗情況。
API 組合模式(API Composition)
API 組合模式是微服務(wù)架構(gòu)中用于解決多服務(wù)數(shù)據(jù)檢索問題的基礎(chǔ)策略。在一個(gè)由多個(gè)微服務(wù)組成、每個(gè)服務(wù)管理各自數(shù)據(jù)片段的環(huán)境中,直接在客戶端進(jìn)行數(shù)據(jù)查詢往往會(huì)變得復(fù)雜和低效。
為解決這一問題,API 組合模式引入了一個(gè)中介層,通常稱為 API 組合器或聚合器。該中介負(fù)責(zé)將來自不同微服務(wù)的數(shù)據(jù)整合為一個(gè)統(tǒng)一的響應(yīng)結(jié)果,從而為客戶端提供了一個(gè)集中的數(shù)據(jù)訪問入口,簡(jiǎn)化了查詢過程并優(yōu)化了數(shù)據(jù)傳輸效率。然而,開發(fā)人員需要確保這個(gè)組合器高效運(yùn)行,避免成為系統(tǒng)的性能瓶頸或單點(diǎn)故障。
命令查詢職責(zé)分離模式(CQRS)
在微服務(wù)架構(gòu)中,數(shù)據(jù)管理通常是分散的,特別是當(dāng)一個(gè)服務(wù)需要同時(shí)負(fù)責(zé)數(shù)據(jù)的更新和查詢時(shí),這會(huì)增加系統(tǒng)復(fù)雜性。
CQRS 通過分離命令操作(即數(shù)據(jù)寫入)和查詢操作(即數(shù)據(jù)讀取)來解決這個(gè)問題。按照這種設(shè)計(jì),微服務(wù)可以根據(jù)其主要職責(zé)進(jìn)行優(yōu)化:某些服務(wù)主要負(fù)責(zé)數(shù)據(jù)讀取,而其他服務(wù)則專注于數(shù)據(jù)寫入。這樣,每個(gè)服務(wù)都能根據(jù)自己的工作負(fù)載進(jìn)行獨(dú)立擴(kuò)展。
雖然 CQRS 在微服務(wù)架構(gòu)中有多個(gè)優(yōu)勢(shì),但它也增加了額外的復(fù)雜性,尤其是在保證服務(wù)間數(shù)據(jù)一致性的方面。因此,在決定是否采用 CQRS 時(shí),需要仔細(xì)評(píng)估系統(tǒng)的具體需求。
事件源模式(Event Sourcing)
事件源模式強(qiáng)調(diào)將應(yīng)用狀態(tài)的所有變化以事件的形式進(jìn)行捕獲和存儲(chǔ)。與僅保存數(shù)據(jù)的當(dāng)前狀態(tài)不同,該模式保存一系列狀態(tài)轉(zhuǎn)換的事件,從而允許系統(tǒng)通過回放這些事件來重構(gòu)狀態(tài)。
在微服務(wù)環(huán)境下,這種方法讓每個(gè)服務(wù)都能維護(hù)自己的歷史狀態(tài),從而增強(qiáng)了服務(wù)之間的自主性和解耦。由于這些事件成為了數(shù)據(jù)的唯一真實(shí)來源,它們可以用于多種用途,從數(shù)據(jù)分析到審計(jì)追蹤。
雖然這種模式很強(qiáng)大,但還需要考慮事件版本控制和數(shù)據(jù)存儲(chǔ)的可擴(kuò)展性。
共享數(shù)據(jù)庫(kù)反模式(Shared Database Anti-pattern)
當(dāng)多個(gè)微服務(wù)或系統(tǒng)組件直接與一個(gè)公共數(shù)據(jù)庫(kù)交互,而不是通過 API 或消息傳遞機(jī)制,就會(huì)出現(xiàn)所謂的“共享數(shù)據(jù)庫(kù)反模式”。這種直接的數(shù)據(jù)庫(kù)訪問方式不僅削弱了各個(gè)服務(wù)的自主性,還可能導(dǎo)致數(shù)據(jù)完整性問題。
采用這種設(shè)計(jì)的系統(tǒng)可能會(huì)面臨安全風(fēng)險(xiǎn),因?yàn)橛锌赡軣o意中暴露敏感數(shù)據(jù)。此外,這樣的設(shè)計(jì)也會(huì)增加系統(tǒng)演進(jìn)的復(fù)雜性,因?yàn)榧词故俏⑿〉臄?shù)據(jù)庫(kù)更改也可能需要多個(gè)服務(wù)進(jìn)行協(xié)調(diào)和調(diào)整。
下一步
無論你選擇哪種數(shù)據(jù)管理策略,都應(yīng)避免陷入“分布式單體”這一陷阱。如果各個(gè)服務(wù)之間沒有做到完全的隔離,這通常會(huì)引發(fā)更多問題。從結(jié)構(gòu)和數(shù)據(jù)庫(kù)角度看,這樣的設(shè)計(jì)仍然具有單體的特性。盡管表面上看似已經(jīng)進(jìn)行了拆分,但實(shí)際上各服務(wù)之間仍然存在大量的耦合,從而導(dǎo)致微服務(wù)的多數(shù)優(yōu)勢(shì)被削弱。
接下來,您需要構(gòu)建 API 接口,這些接口將負(fù)責(zé)微服務(wù)與單體應(yīng)用以及其他微服務(wù)之間的通信。API 將從被調(diào)用的服務(wù)獲取必要的數(shù)據(jù)。
步驟 4:優(yōu)化服務(wù)間通信
在設(shè)計(jì)服務(wù)間的通信策略時(shí),需要考慮交互模式。通常,服務(wù)間的交互可以分為兩類:
- 每個(gè)客戶端請(qǐng)求由單一服務(wù)處理(一對(duì)一交互)
- 多個(gè)服務(wù)共同參與處理一個(gè)請(qǐng)求(一對(duì)多交互)
同時(shí),還需要考慮交互的同步或異步特性:
- 同步交互:在這種模式下,客戶端發(fā)送請(qǐng)求后會(huì)等待服務(wù)端的即時(shí)響應(yīng),期間可能會(huì)被阻塞。這是一種直接的、同步的交互方式。
- 異步交互:與同步交互不同,異步模式下客戶端在發(fā)送請(qǐng)求后不會(huì)被阻塞。服務(wù)端的響應(yīng)可能不會(huì)立即到達(dá)。這通常通過消息代理來實(shí)現(xiàn):一個(gè)獨(dú)立的軟件組件負(fù)責(zé)維護(hù)數(shù)據(jù)通道。一個(gè)服務(wù)在該通道上發(fā)布消息,而需要這些消息的服務(wù)則訂閱它。這樣,各服務(wù)可以在合適的時(shí)機(jī)異步地處理這些數(shù)據(jù)。
從業(yè)務(wù)邏輯的角度來看,如果某個(gè)任務(wù)可以異步完成,那么最好采用異步方式。這不僅提高了系統(tǒng)的穩(wěn)定性,還有助于實(shí)現(xiàn)負(fù)載均衡。
步驟 5:測(cè)試與部署
在微服務(wù)測(cè)試方面,與傳統(tǒng)單體應(yīng)用有明顯的不同。在單體應(yīng)用架構(gòu)中,整個(gè)程序可以作為一個(gè)緊密耦合的單元進(jìn)行全面測(cè)試。然而,在微服務(wù)架構(gòu)中,應(yīng)用由多個(gè)服務(wù)組成,這些服務(wù)可能無法同時(shí)進(jìn)行測(cè)試,從而增加了端到端測(cè)試的復(fù)雜性。這一點(diǎn)要求我們采用不同的測(cè)試策略。
針對(duì)微服務(wù),我們通常會(huì)進(jìn)行以下幾種類型的測(cè)試:
- 單元測(cè)試:專門針對(duì)單一服務(wù)的功能性進(jìn)行測(cè)試。
- 集成測(cè)試:確保不同服務(wù)之間能夠順暢地協(xié)同工作。
- 性能測(cè)試:評(píng)估整個(gè)系統(tǒng)的響應(yīng)速度和穩(wěn)定性。
- 組件測(cè)試:對(duì)單個(gè)服務(wù)的各個(gè)組件進(jìn)行測(cè)試。
- 契約測(cè)試:驗(yàn)證用戶與服務(wù)間的交互是否符合預(yù)定規(guī)范。
- 端到端測(cè)試:全面檢查應(yīng)用程序的性能和功能。
這些測(cè)試類型旨在確保微服務(wù)不僅單獨(dú),而且在整體上都能滿足業(yè)務(wù)需求。然而,測(cè)試微服務(wù)也面臨一系列挑戰(zhàn)。
例如,一個(gè)微服務(wù)中出現(xiàn)的錯(cuò)誤可能會(huì)引發(fā)一連串的問題,這大大增加了根因分析的復(fù)雜性。由于微服務(wù)間通常通過多種方式和協(xié)議進(jìn)行通信,這就需要具備專門的技術(shù)知識(shí)和能力。加上需要測(cè)試多個(gè)接口點(diǎn),并且自動(dòng)化測(cè)試在這里尤為重要,因此熟練掌握腳本編寫和自動(dòng)化測(cè)試工具變得尤為關(guān)鍵。
微服務(wù)開發(fā):挑戰(zhàn)與最佳方案
微服務(wù)開發(fā)面臨一系列特有的挑戰(zhàn),因此需要一套全面的方法論來應(yīng)對(duì)。對(duì)這些問題的早期認(rèn)識(shí)和解決,是微服務(wù)成功部署的關(guān)鍵。
數(shù)據(jù)一致性
在微服務(wù)架構(gòu)中,確保各個(gè)服務(wù)之間事務(wù)的準(zhǔn)確性和數(shù)據(jù)的一致性是一大挑戰(zhàn)。雖然沒有一種“萬能”的解決方案,但有一些普遍適用的管理數(shù)據(jù)的原則。
在需要強(qiáng)一致性的業(yè)務(wù)場(chǎng)景中,某個(gè)服務(wù)可以作為特定數(shù)據(jù)實(shí)體的主要數(shù)據(jù)源。其他服務(wù)可以通過 API 接口來訪問這個(gè)主數(shù)據(jù)源。某些服務(wù)可能會(huì)維護(hù)部分?jǐn)?shù)據(jù)副本或版本,但這些都應(yīng)與主數(shù)據(jù)源保持一致。
以電子商務(wù)系統(tǒng)為例,可能存在一個(gè)專門處理客戶訂單的服務(wù)和一個(gè)負(fù)責(zé)推薦的服務(wù)。推薦服務(wù)雖然能感知訂單服務(wù)的活動(dòng),但在如客戶退款等特殊情況下,訂單服務(wù)仍然是完整交易記錄的權(quán)威來源。
因此,經(jīng)驗(yàn)豐富的開發(fā)者需要先了解具體業(yè)務(wù)場(chǎng)景的需求。然后,他們可以靈活選擇最適合的數(shù)據(jù)一致性保證方法。
團(tuán)隊(duì)組織與協(xié)作
在微服務(wù)的開發(fā)過程中,不同的團(tuán)隊(duì)可能有各自的管理風(fēng)格和開發(fā)方法論。因此,建立一個(gè)明確的團(tuán)隊(duì)間溝通和協(xié)作機(jī)制是至關(guān)重要的,尤其是當(dāng)工作需要在內(nèi)部團(tuán)隊(duì)和外包團(tuán)隊(duì)之間協(xié)作時(shí)。
一個(gè)高度正規(guī)的組織結(jié)構(gòu)可能讓各團(tuán)隊(duì)能有效地開發(fā)自己的服務(wù)。然而,如果忽視與其他團(tuán)隊(duì)服務(wù)的集成,可能會(huì)出現(xiàn)數(shù)據(jù)格式不一致等問題。因此,項(xiàng)目中需要有一個(gè)“協(xié)調(diào)者”角色,負(fù)責(zé)統(tǒng)籌各個(gè)團(tuán)隊(duì)的工作。
從更高的層面來看,康威定律告訴我們,軟件系統(tǒng)的架構(gòu)往往會(huì)反映其開發(fā)團(tuán)隊(duì)的組織結(jié)構(gòu)。因此,如果目標(biāo)是構(gòu)建一個(gè)由多個(gè)自治服務(wù)組成的系統(tǒng),那么首先應(yīng)該組織多個(gè)小型、自治的開發(fā)團(tuán)隊(duì),并確保他們能夠有效地進(jìn)行溝通和協(xié)作。
DevOps 的角色與挑戰(zhàn)
在微服務(wù)架構(gòu)中,DevOps 扮演著至關(guān)重要的角色,因?yàn)檫@種架構(gòu)本身具有更高的復(fù)雜性。在這樣的環(huán)境下,需要精細(xì)地協(xié)調(diào)各個(gè)微服務(wù)的部署,以確保它們能夠無縫地互相協(xié)作。這尤其重要,因?yàn)槲⒎?wù)之間通常是緊密相連的,并且可能會(huì)有向后不兼容的變更。因此,提前解決所有依賴關(guān)系并采用靈活的工具,如 Kubernetes 和 Docker,非常關(guān)鍵。DevOps 工程師在這方面起到了至關(guān)重要的支持作用。
此外,微服務(wù)架構(gòu)也使得故障排查更加具有挑戰(zhàn)性。與單體架構(gòu)相比,在微服務(wù)環(huán)境中,準(zhǔn)確地定位問題的根源更加困難。這是因?yàn)橐粋€(gè)服務(wù)可能會(huì)接收數(shù)據(jù)并傳遞給另一個(gè)服務(wù),這樣就增加了確定問題所在環(huán)節(jié)的復(fù)雜性和耗時(shí)。為了解決這一問題,必須集成集中式的日志聚合工具、部署編排系統(tǒng)和分布式追蹤系統(tǒng)。這樣做能讓整個(gè)系統(tǒng)更容易管理。
總結(jié)與建議
當(dāng)企業(yè)決定向微服務(wù)架構(gòu)遷移時(shí),需要全面考慮多個(gè)方面。這包括確定哪些系統(tǒng)組件適合遷移到微服務(wù)、如何管理數(shù)據(jù)、如何構(gòu)建高效的基礎(chǔ)設(shè)施,以及如何組織和協(xié)調(diào)團(tuán)隊(duì)的工作。在這一過程中,與經(jīng)驗(yàn)豐富的工程師和解決方案架構(gòu)師的緊密合作是實(shí)現(xiàn)目標(biāo)的關(guān)鍵。
譯者介紹
劉汪洋,51CTO社區(qū)編輯,昵稱:明明如月,一個(gè)擁有 5 年開發(fā)經(jīng)驗(yàn)的某大廠高級(jí) Java 工程師,擁有多個(gè)主流技術(shù)博客平臺(tái)博客專家稱號(hào)。
原文標(biāo)題:How to Migrate from Monolith to Microservices: Challenges and Best Practices,作者:MobiDev