架構模組化#

架構模組化(architectural modularity)描述的是將大型單體應用程式拆分為更小、獨立部署單元的過程。但架構師不應僅因技術原因就拆分系統——必須有明確的商業驅動因素(business drivers)作為支撐。

建立拆分系統的商業論據(business case)需要三個步驟:理解架構模組化的好處、將好處對應到當前系統面臨的問題、分析並記錄拆分的 trade-offs

為什麼需要模組化#

  • 持續變化的商業環境:併購、市場競爭加劇、消費者需求增長、技術創新(AI/ML)都要求底層架構能快速適應
  • 可擴展性:大型單體應用如同一個裝滿水的杯子——加第二個杯子無濟於事,因為水量相同。拆分應用後,水可以分裝到兩個半滿的杯子,提供 50% 的成長空間

Figure 3.1: A full glass representing a large monolithic application close to capacity

Figure 3.2: Two half-full glasses representing an application broken apart with plenty of room

  • 敏捷性(agility):快速回應變化的能力,透過 speed-to-market 實現,是在市場中取得競爭優勢(competitive advantage)的關鍵

Modularity Drivers#

將應用程式拆分為更小部分的主要商業驅動因素包括 speed-to-market競爭優勢。支撐這些目標的五個關鍵架構特性為:

  • Availability(可用性 / 容錯能力)
  • Scalability(可擴展性)
  • Agility(敏捷性)——由以下三者組成:
    • Deployability(可部署性)
    • Testability(可測試性)
    • Maintainability(可維護性)

Figure 3.3: The drivers for modularity and the relationships among them

架構模組化不一定意味著必須轉為分散式架構。可維護性、可測試性和可部署性也能透過 modular monolith 或 microkernel 等單體架構實現。

Maintainability#

可維護性是指新增、修改或移除功能的容易程度,也包括維護性修補、框架升級等。

衡量可維護性的典型指標:

  • Component coupling:元件之間相互了解的程度
  • Component cohesion:元件內部操作的關聯程度
  • Cyclomatic complexity:元件內的間接引用和巢套層級
  • Component size:元件內的程式碼量
  • Technical vs domain partitioning:元件按技術用途或領域目的分組

變更範圍隨架構風格而不同:

  • 單體式分層架構:變更在應用程式層級(application level)傳播——修改一個願望清單功能需要跨 UI、業務邏輯、持久層三個團隊協調

Figure 3.4: With monolithic layered architectures, change is at an application level

  • Service-based 架構:變更在領域層級(domain level)——只需修改對應的領域元件

Figure 3.5: With service-based architectures, change is at a domain level

  • 微服務架構:變更在功能層級(function level)——變更被隔離在負責該功能的特定服務中

Figure 3.6: With microservices architectures, change is at a function level

Testability#

可測試性包括測試的容易度(通常透過自動化測試)和測試的完整度

  • 大型單體架構的可測試性低——完整迴歸測試困難,開發者經常面對數百甚至數千個不相關的測試失敗
  • 架構模組化顯著縮小測試範圍,讓測試更有針對性
  • 但當服務間的通訊增加時,測試範圍也會隨之擴大,削弱可測試性的改善

Figure 3.7: Testing scope is increased as services communicate with one another

Deployability#

可部署性不僅關乎部署的容易程度,還包括部署的頻率風險

  • 單體架構的部署問題:code freeze、mock deployment、高風險、部署間隔長(數週到數月)
  • 模組化後的好處:
    • 更少的部署儀式
    • 更低的部署風險
    • 更高的部署頻率

如果微服務必須以特定順序作為一個完整組合來部署,請把它們放回單體架構,省去麻煩。這種情況被稱為「分散式泥球」(big ball of distributed mud)。

Scalability#

  • Scalability(可擴展性):系統在使用者負載逐漸增長時維持回應能力的能力
  • Elasticity(彈性):系統在瞬間大量使用者湧入時維持回應能力的能力

兩者雖然相關但處理方式不同:

架構風格ScalabilityElasticity擴展層級
Monolithic layeredApplication-level
Service-based中高Domain-level
MicroservicesFunction-level
  • Elasticity 更依賴服務的粒度(granularity),需要極短的 Mean Time to Startup (MTTS)
  • 服務間的同步通訊越多,對可擴展性和彈性的負面影響越大

Figure 3.8: Scalability is different from elasticity

Figure 3.9: Scalability and elasticity improve with modularity

Availability / Fault Tolerance#

容錯能力:當系統的某些部分故障時,其餘部分仍能維持回應和可用的能力。

  • 所有單體系統都有低容錯能力——即使透過多實例負載平衡也是昂貴且低效的
  • 架構模組化是實現領域層級和功能層級容錯的關鍵——災難性故障被隔離在該部署單元
  • 注意:若其他服務同步依賴一個故障中的服務,容錯仍然無法實現——因此非同步通訊對維持分散式系統的容錯至關重要

Sysops Squad Saga: Creating a Business Case#

Addison 和 Austen 將模組化驅動因素對應到 Sysops Squad 的實際問題,建立了遷移到分散式架構的商業論據:

  • Maintainability:程式碼庫太大、太耦合,開發者難以找到修改位置,變更經常引發其他問題
  • Testability:超過 30% 的測試案例已被註解或過時,每次變更都必須執行整套測試,開發者被迫修復不相關的測試失敗
  • Deployability:因為是單體架構,即使是小型 bug fix 也必須部署整個系統,部署風險高,每月才能發布一次
  • Fault tolerance:報表和客戶滿意度調查功能的問題會拖垮核心的工單(ticketing)功能
  • Scalability:超過 25 位客戶同時建立工單時系統凍結,報表作業也會導致系統停頓——同時存在可擴展性和資料庫負載問題

最終,Addison 撰寫了一份 Architecture Decision Record (ADR),記錄遷移到分散式架構的決定,獲得了商業贊助者的同意。