譯者 | 劉汪洋
審校 | 重樓
當單體架構成為項目增長的瓶頸時,遷移到微服務架構就成了必然的選擇。

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






