1. 簡介與概述
本內容源自《軟體工程廣播》播客第213集,其中Johannes Thönes與James Lewis針對微服務主題進行了討論。這場對話探討了此種架構風格的定義、動機及實務考量。在2015年初,作為應對維護大型單體應用程式挑戰的回應,微服務架構正獲得極大的關注。
2. 定義微服務
微服務被概念化為一個小型、聚焦的應用程式元件。
2.1 核心特性
根據討論,一個微服務具備以下幾個關鍵屬性:
- 獨立部署:無需修改其他服務即可部署。
- 獨立擴展:可根據其特定負載進行水平或垂直擴展。
- 獨立測試:可以隔離驗證。
- 單一職責:只有一個主要的變更或替換理由。它執行一個內聚的任務,且易於理解。
2.2 單一職責範例
微服務所做的「單一事情」可以是功能性的或跨功能性的(非功能性):
- 功能性:提供特定領域資源(例如:使用者服務、文章服務、保險中的風險計算服務)。
- 跨功能性:一個讀取訊息、套用業務邏輯並傳遞下去的佇列處理器。負責特定的非功能性需求,如快取或日誌記錄。
3. 微服務的興起
3.1 流行驅動因素
微服務的流行歸因於一個普遍的產業痛點:難以管理的單體應用程式。組織面臨著經過5-10年發展、變得難以修改、難以作為SaaS部署或在雲端有效擴展的應用程式。
3.2 解決技術債
微服務作為一種解決方案出現,旨在將這些單體應用拆分為更小、協同運作、在外部程序執行的元件。這種方法由Netflix等公司大規模展示,允許獨立維護、擴展和替換。其核心驅動力是需要更快地交付軟體,並利用持續交付等實踐,而這些實踐受到單體架構的阻礙。
4. 採用與實作模式
4.1 綠地開發 vs. 棕地開發
一個關鍵問題是應該從頭開始新專案時就採用微服務(綠地開發),還是將現有的單體應用重構為微服務(棕地開發)。討論指出,根據經驗,大多數組織從單體應用開始,之後再進行重構,面臨著在現有程式碼庫中識別有界上下文和接縫的挑戰。
4.2 運維複雜性
播客摘錄提到,篇幅限制無法完整討論運維複雜性及其對DevOps的影響。這意味著,雖然微服務解決了開發和擴展性問題,但它們在監控、部署編排和網路可靠性方面引入了新的挑戰。
5. 關鍵見解與分析
核心見解
微服務並非萬靈丹技術;它們是對單體開發瓶頸的一種組織與經濟回應。正如Netflix範例所暗示的,其真正的價值主張在於實現獨立、並行的價值交付流程。這種架構直接針對困擾著在單一程式碼庫上工作的大型團隊的協調成本和部署摩擦,這個問題由Melvin Conway的格言形式化:「設計系統的組織……其產生的設計必然是這些組織溝通結構的複製品。」微服務試圖透過設計能強制產生理想溝通結構的系統來逆轉這一點。
邏輯流程
敘述遵循一個引人注目的因果鏈:(1) 單體應用累積技術債並變得難以變更。(2) 業務要求雲端擴展性和持續交付。(3) 單體架構因其耦合性而與這些目標根本不相容。(4) 解決方案是沿著有界上下文拆分單體,建立可獨立部署的單元。這個邏輯是合理的,但忽略了巨大的中間複雜性——即「如何」拆分的問題。
優點與缺陷
優點:將獨立部署能力作為首要特性的關注點非常準確。這是解鎖團隊自主權和更快發布週期的關鍵。與康威定律和CQRS(被提及為省略的主題)的連結,顯示了對更深層次社會技術模式的認識。
缺陷:2015年的觀點明顯對定義「單一職責」的容易度過於樂觀。後續的產業經驗揭示這是最困難的部分——定義不清的服務邊界導致分散式單體的詛咒。摘錄也危險地輕描淡寫了運維開銷。正如後來的Fowler經典文章所闡述,你以開發複雜性換取運維複雜性。將Docker稱為「一個流行的工具」是一個歷史快照;容器化生態系統是當時缺失的運維推動者,它使得微服務在大規模應用中變得實際可行。
可行動的見解
對於領導者:不要因為微服務流行就從它開始。先衡量你的變更前置時間和部署頻率。如果它們因為程式碼庫協調問題而表現不佳,再考慮微服務。對於架構師:主要的設計工具不是技術檢查清單,而是領域驅動設計(DDD)的上下文映射圖。根據業務能力而非技術層次來定義邊界。對於團隊:預先投資於平台工程——自動化部署、服務發現和可觀測性不是事後才考慮的;它們是基礎。建議的路徑——從單體應用重構——仍然是最明智的。使用絞殺者模式來逐步用服務替換單體應用的部分,因為這可以管理風險並允許學習。
6. 技術框架與數學模型
雖然播客是對話形式,但其基本原則可以形式化。一個關鍵模型是團隊規模(N)、溝通路徑和架構耦合度之間的關係。
在一個有N個團隊的單體架構中,潛在的溝通路徑以$O(N^2)$的規模增長,因為一個模組的變更可能影響許多其他模組。這產生了協調開銷。微服務旨在透過強制有界上下文和API來減少這種開銷。目標是透過網路呼叫,使跨服務溝通成本$C_{comm}$明確地變高,從而鼓勵在服務內部建立強模組化,其中變更成本$C_{internal}$較低。
變更傳播機率($P_{prop}$)的一個簡化模型可能是:
$P_{prop} \approx \frac{C_{comm}}{C_{comm} + C_{internal}}$
在一個設計良好的微服務架構中,透過使$C_{comm}$(網路延遲、API版本控制)成為跨邊界變更的主導因素,來最小化不相關變更的$P_{prop}$。
7. 實驗結果與個案研究
播客引用Netflix作為主要個案研究。到2015年,Netflix已將其單體後端著名地分解為數百個微服務,從而實現:
- 獨立擴展:像電影推薦或帳單服務可以在高峰負載期間獨立擴展。
- 快速創新:團隊可以每天多次部署其服務,而無需全端協調。
- 技術異質性:不同的服務可以用最適合其任務的語言編寫(例如:Java、Node.js)。
圖表描述(假設性):一個條形圖,在兩個軸上比較單體應用程式與微服務架構:(1) 部署頻率(部署/天):單體顯示低條(例如:0.1),微服務顯示高條(例如:50+)。(2) 從故障中恢復的平均恢復時間(MTTR):單體顯示高條(例如:4小時),微服務顯示較低的條(例如:30分鐘),因為故障可以隔離到特定服務。
後續的研究,例如DevOps狀態報告中引用的那些,已經統計上將鬆散耦合、面向服務的架構與更高的軟體交付效能相關聯。
8. 分析框架:實務範例
情境:一個電子商務單體應用在更新上遇到困難。「結帳」功能的變更需要完整的回歸測試,並與「產品目錄」的更新衝突。
框架應用:
- 識別有界上下文:使用領域驅動設計,識別核心領域:訂單處理、產品目錄、庫存、使用者管理、支付。
- 定義服務邊界:為每個上下文建立一個微服務。訂單服務擁有結帳邏輯和訂單資料。
- 建立合約:定義清晰的API。訂單服務將呼叫支付服務的
processPayment(orderId, amount)API和庫存服務的reserveStock(itemId, quantity)API。 - 資料所有權:每個服務擁有自己的資料庫。訂單服務有自己的「orders」資料表;它不直接查詢庫存資料庫。
- 部署與可觀測性:每個服務都被容器化,獨立部署,並將指標(延遲、錯誤率)發布到中央儀表板。
成果:結帳團隊現在可以部署訂單服務的更新,而無需涉及目錄或庫存團隊,顯著減少了協調開銷並提高了部署頻率。
9. 未來應用與研究方向
微服務的演進超越了2015年的觀點:
- 服務網格:像Istio和Linkerd這樣的技術已經出現,用於在基礎設施層處理橫切關注點(安全性、可觀測性、流量管理),減輕了單個服務的程式碼負擔。
- 無伺服器與FaaS:函數即服務(例如:AWS Lambda)代表了微服務的一種極端形式,將運維複雜性完全推給雲端供應商,並實現更細粒度的擴展。
- AI/ML整合:微服務正成為部署ML模型作為獨立預測服務的事實標準模式,允許進行A/B測試和演算法的快速迭代。
- 邊緣運算:將輕量級微服務部署到邊緣設備,用於物聯網和即時分析場景中的低延遲處理。
- 研究重點:未來的研究需要關注自動化服務分解工具、分散式系統中的智慧故障預測,以及服務編排互動的形式化驗證。
10. 參考文獻
- Lewis, J., & Fowler, M. (2014). Microservices. MartinFowler.com. 取自 https://martinfowler.com/articles/microservices.html
- Newman, S. (2015). Building Microservices. O'Reilly Media.
- Forsgren, N., Humble, J., & Kim, G. (2018). Accelerate: The Science of Lean Software and DevOps. IT Revolution Press.
- Conway, M. E. (1968). How Do Committees Invent? Datamation, 14(5), 28-31.
- Google Cloud. (2019). The 2019 Accelerate State of DevOps Report. DORA.
- Netflix Technology Blog. (Various). https://netflixtechblog.com/