本章概覽#

第 6 章說明巨石架構在許多情境下是合適選擇,但當業務關鍵應用真的變得龐大,應用與其開發組織就會超過巨石的承載能力——五個流暢交付品質屬性(可修改性、可測試性、可部署性、可觀測性、可演化性)再也滿足不了。這時,遷移到微服務架構才有意義。

第 1 章已給出微服務架構的定義並說明它如何促進流暢交付。本章在那個基礎上深入展開:

  • 結合第 3 章(架構基礎)與第 4 章(四種耦合)的概念,重新檢視微服務架構的定義
  • 探討微服務如何支援第 5 章的五個流暢交付品質屬性。
  • 更深入分析微服務的缺點與採用挑戰。
  • 介紹微服務架構模式語言(microservice architecture pattern language)。

本章將討論的主題#

  • 微服務架構為何能在大規模情境下促成流暢交付
  • 微服務架構的缺點
  • 微服務架構模式語言概覽

微服務架構是什麼#

微服務架構是一種架構風格,把應用的子領域組織成兩個或更多的元件(亦稱「服務」),這些元件獨立可部署且鬆耦合

這個定義包含五個關鍵概念:

  • 它是一種架構風格(architectural style)。
  • 應用由兩個或以上的服務組成,每個服務都是一個元件(可部署單元)。
  • 服務由子領域組成。
  • 服務鬆耦合。
  • 服務可獨立部署。

Figure 7.1: A simple microservice architecture with three services (Order, Delivery, Consumer) plus an API Gateway

與其他常見定義對比#

Martin Fowler 與 James Lewis 的經典定義:

「微服務風格是把單一應用開發為一群小服務的方式,每個服務在自己的 process 中運行,以輕量機制(常為 HTTP RESTful API)互相溝通。這些服務圍繞**業務能力(business capabilities)**建構,由全自動部署機制獨立部署;最低限度的中央管理,服務可使用不同程式語言與不同資料儲存技術。」

Adrian Cockcroft 較簡潔的版本:「鬆耦合的服務導向架構,具備有界上下文(bounded contexts)。」

與 Fowler 定義的相同之處#

  • 圍繞業務概念組織(Fowler 用「business capabilities」,作者用「subdomains」,可由 business capabilities 推導,第 20 章詳述)。
  • 獨立可部署。
  • 自動化部署(作者定義雖未明說,但第 5 章說明流暢交付要求自動化部署管線)。
  • 多技術棧(作者定義雖未明說,但「服務即元件」隱含了這一點)。

與 Fowler 定義的差異#

  • 大小:作者刻意不提服務的大小——「micro」字面化會誤導組織做出過度細粒度架構。目標是滿足品質屬性,不是讓服務變小
  • 可替換性(Replaceability):作者不視「拋棄重寫」為微服務的重要目標,尤其在它需要一堆小服務時。即便元件只有一個技術棧,只要保留 API,內部子領域或更小的元素仍是可替換的。
  • 通訊技術:作者不指定特定 IPC 技術——REST、messaging 等各有取捨(第 3 章詳述)。
  • 鬆耦合:作者把鬆耦合明確列為定義特徵之一。第 4 章已說明它的核心地位,7.3.2 會解釋它在微服務裡為何特別關鍵。

微服務架構不只是「服務」#

定義只觸及到元件視角。微服務架構至少還有三個重要面向:

  • 系統操作:存在於服務之間的「空隙」——跨服務的分散式操作遠比本地操作複雜,會反過來限制子領域如何被切分到服務。
  • 建置架構維度:獨立部署的需求會塑造程式碼倉、建置專案、部署管線。
  • 服務與團隊的關係:適切的對應關係是流暢交付的關鍵。

服務的結構#

  • 服務由一或多個子領域組成。
  • 服務有 API(operations + events)。
  • 服務可能消費其他服務的 API。
  • 服務通常有自己的資料庫——但是私有實作細節,藏在服務 API 後面。

範例:Order Service 包含 Order Management 與 Money 兩個子領域;前者只在 Order Service,後者是被多個服務共用的 library。

Figure 7.2: A service consists of one or more subdomains, has an API of operations and events, may collaborate with other services

API 內容:

  • 部分操作對應系統操作(Order Service.createOrder() 對應 createOrder() 系統操作)。
  • 部分操作純粹是服務間協作用(Consumer Service.reserveCredit()Order Service.createOrder() 呼叫)。

系統操作的兩種類型#

  • 本地操作(local):單一服務完整處理。例:createConsumer()
  • 分散式操作(distributed):跨多個服務。有「進入點」服務,該服務再與其他服務協作完成請求。例:createOrder()

分散式操作幾乎永遠比本地操作複雜得多——後續 7.5.1 會深入分析原因。

Figure 7.3: Two types of system operations — local (single service) and distributed (span multiple services)

建置架構#

兩種主要做法:

  • multi-repo:每個服務一個程式碼倉、一個建置專案、一個部署管線。各自獨立測試與部署,擴張容易;全域變更(例如依賴升級)需跨多個 repo 協調,較難。
  • monorepo:所有服務放在單一 repo。全域變更最容易;但要做到真正獨立部署很有挑戰,大型 monorepo 還需要在 build system 上大量投資,容易喧賓奪主。

Figure 7.4: Multi-repo build architecture — each service has its own deployment pipeline

服務 ⇔ 團隊的關係#

理想狀況:每個服務由單一團隊擁有——服務間鬆設計期耦合,團隊就能獨立開發、測試、部署。

但「服務 = 團隊」並非嚴格 1:1。一個服務可能包含多個子領域、多個團隊擁有(例如 Consumer Service 同時包含由 Consumer Management team 擁有的 Consumer Management 子領域,以及由 Order Management team 擁有的 Money 共用 library)。有時即使犧牲一些團隊自主性,也得把兩個非函式庫子領域併進同一個服務——例如網路通訊成本過高無法接受(第 20 章詳述)。

微服務架構的兩個必要特徵#

必要特徵 #1:服務可獨立部署#

「獨立可部署」有三個層面:

  • 服務必須是元件(component):可執行 JAR、OS 執行檔、container image、Lambda zip 等;不是要打包進其他元件的 library。
  • 服務必須有自己的部署管線:沒有獨立管線就無法獨立部署——必須跟別的服務一起部署、與其他團隊協調,自主性大打折扣。
  • 服務在被獨立測試後即生產 ready:管線跑出的服務即可上生產,不需要其他服務一起測試;Client 與 collaborator 用 test double 模擬。

Figure 7.5: A service must be independently deployable — packaged, has its own pipeline, production-ready after isolated testing

隔離測試的兩個關鍵:

  • 刻意設計簡單、明確、穩定的 API,讓 client 與 collaborator 易於模擬。
  • consumer-driven contract test(消費者驅動契約測試,第 15、16 章詳述)驗證雙方對 API 的共識——契約破損就 fail,不需要把服務一起跑。

為什麼有人放棄 contract test?#

Chris Richardson 觀察到的故事:某組織說 contract test「太麻煩」,改回應用層級端到端測試。

真正的根因往往是:過度細粒度且設計期緊耦合的架構,讓 contract 又多又不穩——這是「More the Merrier」反模式的副作用,而不是 contract test 本身的問題。

獨立部署的兩大好處#

  • 加速、簡化、提升管線可靠性:擺脫慢、複雜、容易隨機失敗的端到端測試。例:測 Order Service 不用先把 Consumer Service 拉起、建立 Consumer 再建立 Order;只測 Order Service,Consumer Service 用 test double 模擬。
  • 減少跨團隊協調:測試耦合會讓一團隊的失敗阻擋另一團隊的釋出;獨立部署讓團隊真正各自快速且安全地發布。

必要特徵 #2:服務鬆耦合#

四種耦合在微服務情境下的含義:

設計期耦合:必須鬆#

服務間設計期緊耦合會帶來高昂的「同步變更」(lock step change)成本——特別跨團隊時。例:Consumer Service 的 API 要做破壞性變更時,Consumer Management team 必須:

  1. 在現有 API 旁加上新版 API。
  2. 等所有 client team 把服務遷移到新版。
  3. 全部遷移後才能刪掉舊版。

破壞性 API 變更是微服務的內在風險之一——所以鬆設計期耦合是必備

執行期耦合:應該盡量鬆#

不至於阻擋流暢交付,但會增加延遲、降低可用性。設計時必須在「服務切分」與「執行期耦合」之間做取捨——必要時把多個子領域合併到同一服務中(第 20 章詳述)。

建置期耦合:通常不是問題#

服務各自獨立建置,服務間不會有建置期耦合;服務內部可能有,但程式碼庫小,管線通常還是快;真有需要可套用第 6 章的物理設計原則。

基礎建設耦合:多半是選擇問題#

取決於部署架構——例如是否共用資料庫伺服器,是「共享便利」與「耦合風險」的取捨。

微服務的好處#

最大的好處是支援流暢交付;此外還有:

支援流暢交付(滿足五大品質屬性)#

  • 高可修改性:服務間鬆設計期耦合,單一服務變更鮮少波及其他服務,團隊高度自主——但需要紀律,持續管理服務間依賴。
  • 高可演化性:多元件架構,技術棧可漸進式升級,一次升一個服務;每個服務還能用最適合自己的技術棧。
  • 高可測試性:服務小且能隔離測試,不需慢且脆弱的端到端測試;每個服務的部署管線只處理少量變更,難變成瓶頸;難測的功能可隔離到自己的服務,不影響其他服務的可測試性。
  • 高可部署性:服務小、獨立部署,部署快且可靠;團隊可不用協調(甚至並行)部署;管線難變瓶頸。
  • 高可觀測性:每個服務各自吐 telemetry,比巨石細緻——若一個服務只裝一個子領域,就能直接得到該子領域層級的觀測資料。

支援多技術棧#

「right tool for the right job」。不過為避免無政府狀態,組織仍要主動管理「核可技術」清單。

試新技術也更容易、更安全:做一個服務、上線、評估;成功代表組織驗證了一個新棧,失敗也只丟掉一個服務的工。

讓組織能擴張#

《Wiring the Winning Organization》(Gene Kim、Steven J. Spear,2023)記錄 Amazon 在 2002 年因為單一巨石而交付速度大幅下降;後來轉為微服務架構(書中稱為「modularization」),到 2025 年據稱每天部署 13 萬次。

新團隊可接手新服務,協調成本極低;每個服務各有部署管線,build 架構隨組織擴張。

改善開發者體驗#

開發者多數時間在自己的小程式碼庫工作,認知負荷低、回饋快、團隊小且獨立;與其他團隊偶爾協作以實作分散式操作。心流(flow)更好,生產力更高

Figure 7.6: From a service developer's perspective, their world is far simpler than working on a monolith

依特徵切分子領域#

子領域常有不同特徵:

  • 資源需求:Order Management 用一般機器,Fraud Detection 需要 GPU(p4d.24xlarge 是 m5.24xlarge 的 8 倍價格);分服務後可獨立 scale,大幅降低成本。

Figure 7.7: Subdomains within the same service are scaled together; separate services enable independent scaling

  • 特定領域法規:醫療軟體要符合 ISO 13485、ISO/IEC 62304,與 DevOps 風格相衝;把受規範子領域隔離成獨立服務,其他可繼續用 DevOps。
  • 業務關鍵性 → 可用性:把關鍵子領域(例如信用卡授權)隔離,避免被低關鍵子領域(例如 Merchant Account 管理)拖垮。
  • 安全性:把處理 PII 等敏感資料的子領域隔離成服務,API 成為安全邊界,可加上防火牆、service mesh 規則、私有子網等網路控制,降低攻擊面。
  • DDD 子領域類型:Core(核心競爭力,自己寫)、Supporting(常見但需客製,可外購但常自己寫)、Generic(常見且不需客製,直接外購);把 core 隔離成服務以加速核心競爭力的迭代。

微服務的缺點#

分散式操作很複雜#

服務同時是行程邊界與交易邊界,設計分散式操作時要面對:

Figure 7.8: Services are process and transaction boundaries, so distributed operations are far more complicated than local operations

  • 網路通訊的成本與延遲:方法呼叫是奈秒級,網路通訊是毫秒級,頻寬有限;但真正的問題不是相對成本,是 SLO 是否被滿足。延遲若超過 SLO,就要選「接受高延遲」或「合併兩個子領域到同一服務(犧牲團隊自主)」。
  • 執行期耦合風險:某些操作的執行期耦合可透過調整邊界消除,某些則必須改變語意(例如 partial outcome 或非同步)才能解決;再次,只有當它讓 SLO 不滿足時才是問題
  • 最終一致性的複雜:傳統 2PC 在現代應用不適用——本身就是執行期耦合,且許多現代資料庫不支援 2PC。較好的做法是把 ACID 限定在單一服務內,跨服務操作以「一連串本地交易」實作,即「最終一致性」。
    • 缺點:更複雜的交易模型;不能依賴 DB 鎖與 rollback;有時要寫補償邏輯;併發要在應用層處理;跨服務查詢無法強一致。
    • 工具:四個服務協作模式——Saga、Command-side replica(分散式 commands);API Composition、CQRS(分散式 queries),第 10、11 章詳述。

Figure 7.9: Distributed transactions are replaced with a sequence of local transactions coordinated by asynchronous messaging

跨服務變更很複雜#

單一服務變更比巨石快、簡單,但跨多個服務的變更比巨石更複雜:

  • 向後相容變更:有部署順序依賴(被依賴方先上線,client 才能用)。
  • 破壞性 API 變更:必須做 3 步——加新版、client 全部遷移、刪舊版,遠比巨石中改一個 commit 多

設計時的核心目標:讓多數變更局限在單一服務內。要做到這點本身就是一大挑戰。

設計微服務架構很困難#

軟體設計的核心是命名、分群、貫徹鬆耦合與高內聚。微服務的設計特別不寬容於錯誤——服務是行程與交易邊界,把兩個被同一系統操作呼叫的子領域分開部署,影響遠比把兩個類別分到不同 package 嚴重。

一不小心就做出分散式巨石:服務間設計期緊耦合(改動連鎖)+ 執行期緊耦合(失敗連鎖),把兩種架構的缺點集大成。

第 20 章探討這個複雜的設計空間:N 個現有服務時,新子領域有 N+1 種放置方式;每種放置方式又有多種系統操作實作模式,各有取捨,且取捨之間常彼此衝突。

營運挑戰#

巨石的部署架構是「同一應用的多個實例」;微服務則是「多個服務 × 多個實例 × 不同(版本的)技術棧」,且容易出現由獨立服務間互動引起的「emergent behavior(突現行為)」。

容器、Kubernetes、現代可觀測性工具能緩解相當多複雜度,但「消化複雜度」永遠是團隊責任。

擁抱獨立部署是組織重大改變#

  • 組織常死守應用層級 user acceptance test,讓「獨立部署」實質失效——這是分散式巨石的常見成因
  • 解法:把這類測試重構為服務層級的 user acceptance test——以白盒方式驗證每個服務在隔離下的行為。
    • 例:Order Service 的 acceptance test 驗證 createOrder() 用預期參數呼叫 reserveCredit(),並正確處理 success / unknown customer / insufficient credit 等結果。
    • Consumer Service 的 acceptance test 驗證 reserveCredit() 在不同信用額度下的行為。
  • 結構上,測試套件的拆解 mirror 應用架構的拆解;許多服務層級 acceptance test 還可寫成快速本地單元測試。

Figure 7.10: Refactor application-level acceptance tests into service-level acceptance tests that test each service in isolation

「服務一起測試 ⇒ 你正在打造分散式巨石」。要嘛改善架構讓服務能各自獨立測試,要嘛乾脆做巨石——折中路線最糟。

巨石遷移到微服務很困難#

需要長期投入(常以「年」為單位),解開 legacy 程式碼、處理大型應用的複雜度——好處夠大才值得(策略與技巧見第 21 章)。

微服務架構模式語言#

Christopher Alexander 在《A Pattern Language: Towns, Buildings, Construction》(1977)為實體建築建立 253 個模式組成的語言;Erich Gamma 等的《Design Patterns》(1994)把這個概念引入軟體領域。

一個模式(pattern) 是針對特定情境下重複出現問題的可重用解決方案。

模式的核心結構#

一個寫得好的模式應包含:

  • Forces:在該情境下解決問題時必須處理的關注點;forces 可彼此衝突,優先順序由情境決定。
  • Resulting context:套用後的後果——好處(被解決的 forces)、壞處(未解決的 forces)、新引入的問題。
  • Related patterns:與其他模式的關係,有五種:predecessor、successor、alternative、generalization、specialization

Figure 7.11: Visual representation of pattern relationships — predecessor, successor, alternative, generalization, specialization

微服務架構模式語言的高層結構#

模式語言分三層:

  • Infrastructure patterns:多在開發以外的基礎設施範疇。
  • Application infrastructure patterns:同時影響開發。
  • Application patterns:服務開發者面對的問題。

Figure 7.12: A high-level view of the microservice architecture pattern language showing problem areas

主要模式群組:

  • Application architecture patterns:Monolithic vs Microservice。
  • Service collaboration patterns:四個——Saga、Command-side replica(commands);API Composition、CQRS(queries)。詳見第 10、11 章。
  • Communication patterns(五群):
    • Communication style(同步 RPC/REST 或非同步 messaging)
    • Transactional messaging(訊息收送與業務交易整合)
    • Reliability(同步通訊在服務或網路有問題時仍可靠)
    • Discovery(client 如何知道某服務實例的網路位置)
    • External API(外部 client 怎麼跟服務溝通)

Figure 7.13: Five groups of communication patterns — communication style, transactional messaging, reliability, discovery, external API

  • Security patterns:常見如 Access Token——API gateway 以 JWT 等令牌把使用者身份與角色傳遞給服務。
  • Patterns for automated testing:Consumer-driven contract testConsumer-side contract testService component test(第 15、16 章)。
  • Service deployment patterns:傳統手動部署無法支撐;需要高度自動化的部署平台(GitOps、容器、無伺服器等),第 12、{chapter-kubernetes} 章詳述。

Figure 7.14: Patterns for deploying microservices — language-specific, VM/container, serverless, deployment platform

  • Observability patterns:Health check API、Log aggregation、Distributed tracing、Exception tracking、Application metrics、Audit logging。
  • Cross-cutting concerns:Service TemplateMicroservice Chassis——降低每個服務重新實作 logging、security、monitoring 等共通邏輯的負擔,並維持一致性。

章節重點摘要#

  • 微服務架構不只是服務的集合:還包括跨服務的系統操作、部署管線/建置架構、服務與團隊的對應關係。
  • 微服務的好處(多源於鬆耦合與獨立可部署):支援流暢交付的五個品質屬性、改善開發體驗、支援多技術棧、讓組織能擴張、用「依特徵切分子領域」改善可用性、安全性、可擴展性等。
  • 分散式架構是雙面刃:跨服務的系統操作(latency、partial failure、最終一致性)是主要挑戰來源。
  • 成功採用必須有意識的設計,避免做出分散式巨石(緊耦合服務,集兩種架構的劣勢)。
  • 團隊必須擁抱「獨立可部署」,以服務隔離測試取代應用層級 acceptance test。
  • 微服務架構模式語言提供「該不該用微服務」與「真的要用,該怎麼解一系列衍生問題」的設計指引。