iT邦幫忙

2025 iThome 鐵人賽

DAY 16
0
Software Development

微服務導入:從觀念到落地的架構實戰地圖系列 第 16

微服務導入 – Day 16 微服務中的資料一致性與資料模式

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20250923/20178262w0GyBPWNNE.png

在先前文章中,我們談到 Database per Service 是微服務架構中比較合理的資料庫設計方式。它能有效確保「低耦合、高自治」,讓每個服務可以獨立演進。然而,一旦我們放棄了「共享資料庫(Shared Database)」這條捷徑,隨之而來的挑戰就是 跨服務的交易一致性與查詢難度。

今天,我們要深入探討四個關鍵的資料模式:
• Saga:跨服務交易一致性的解決方案
• Aggregate:一致性邊界的最小單位
• Event Sourcing:用事件取代狀態,記錄完整業務歷程
• Domain Event:用事件驅動服務之間的協作

這四個模式構成了微服務架構中「資料一致性」的核心工具箱。

https://ithelp.ithome.com.tw/upload/images/20250920/20178262jfEZPddgBw.jpg


Saga 模式取代傳統 ACID 的交易服務

在過去,我們只要一個 資料庫交易(Transaction) 就能保證 ACID(原子性、一致性、隔離性、持久性)。但在微服務架構下,每個服務都有獨立的資料庫,傳統的分散式交易(Two-Phase Commit, 2PC)不但效能差,還和 NoSQL 資料庫的特性不相容。

Saga 的解法

Saga 將一個跨服務的「長交易」拆解成一連串的「本地交易」。每個本地交易都只會修改單一服務的資料,並且在完成後 觸發下一個服務的交易。如果中間有步驟失敗,Saga 就會呼叫「補償交易(Compensation Transaction)」來回滾。

實作方式

(1) Orchestration
由一個「協調者」負責控制交易流程,決定下一步由哪個服務執行,是一種「集中管理」的處理模式。

【範例】
訂單服務啟動 Saga,依序呼叫「支付服務 → 庫存服務 → 出貨服務」。若庫存不足,協調者會通知支付服務     進行退款。

(2) Choreography
沒有中央協調者,服務跟服務之間透過事件互相觸發,在這個模式下高度解耦,擴展性佳,但難以追蹤管控。

【範例】
訂單服務發佈「OrderCreated」事件 → 支付服務監聽後處理扣款 → 扣款成功再發佈「PaymentCompleted」事件 → 庫存服務接手。

效益與副作用

Saga 模式可以解決「微服務的自治性」,不依賴共用資料庫的交易管理特性,也讓我們得以選用 NoSQL 的技術實現分散式運算的機制。但,它與傳統模式不同的是開發複雜度較高,可能還需要實作「補償交易」等相關機制。開發複雜度高也就暗示設計錯誤可能遭致「資料不一致」的狀況。

在 Saga 中提到,我們可能要實作「補償交易」等相關機制,回想我們目前的營運工作,你有多少次直接打開 DB 工具修改裡面的資料?在微服務的架構下,你繞過應用程式修改一個資料可能就會造成系統間資料不一致的狀況 (事件可能都沒被正常的丟出來)。


Aggregate (聚合)

Aggregate 是領域驅動設計(DDD)戰術設計的核心概念,也是微服務中劃分服務邊界的重要參考。

Aggregate 的定義

Aggregate 指的是一群高度相關的 Entity(實體) 與 Value Object(值物件) 的集合,並由一個 Aggregate Root(聚合根) 作為唯一入口。任何修改操作,都必須透過聚合根來進行。

https://ithelp.ithome.com.tw/upload/images/20250921/20178262dL85D8611R.jpg

從圖中,我們也可以看出上述元件之間互相的關係。

Aggregate 實作原則

(1) 一致性邊界:Aggregate 內的資料必須在交易完成後保持一致。
(2) Aggregate Root:外部只能透過 Root 存取 Aggregate。
(3) 邊界大小:太大會導致更新衝突,太小會產生過多跨 Aggregate 交易。

【範例】
(1) Entity : 訂單、商品、庫存以上是訂單管理系統的三個概念
(2) 假設上述三個概念個自形成三個 aggregate 的話,意即我們有可能建立出三個微服務
(3) Value Object: 商品架構、送貨地址等相關資訊 (沒有 Identity 的物件)
(4) 確保一致性的業務規則:一張訂單中的所有項目必須在提交時同時驗證庫存
4.1. 下單的時候,訂單狀態為「WAIT_STOCK」等待庫存確認
4.2. 待「庫存」服務確認後,訂單狀態才會被修改為「CONFIRMED」

訂單不直接查/改庫存;庫存是否足夠由庫存聚合保證,訂單只依據「已預留成功」這個外部事實決定是否確認。

Aggregate 與微服務

Aggregate 提供了判斷「服務邊界」的一個標準:

  • 若一組業務邏輯需要強一致性,就應該被放在同一個 Aggregate(甚至同一個服務)。
  • Aggregate 的邊界常常就是微服務的最小單位。

Event Sourcing 用事件保存歷程

在傳統的 State Sourcing 下,我們只保存資料的「最新狀態」。但有時候,我們需要知道「資料是如何演變而來的」。

Event Sourcing 的核心思想是:

  • 不直接保存狀態,而是保存「事件流」。
  • 狀態可以由事件重播(Replay)計算出來。

目前我見過的應用程式,99.9% 都是 State Sourcing 的實作模式 (那麼那 0.1% 是怎麼來的?從教學上看來的!)

Event Sourcing vs State Sourcing

特性 State Sourcing Event Sourcing
儲存內容 最新狀態 所有事件
儲存量
可追溯性
查詢便利性 需重播或建立投影
一致性支援 ACID 最終一致性
適用場景 傳統 CRUD 系統 金融交易、稽核、IoT 事件流

【範例】

  • 事件:Deposited $100、Withdrew $50、Deposited $200 (這些會被存放在 Event Store)
  • 狀態:Replay 後得出餘額 250

Event Sourcing 的效益與副作用

Event Sourcing 模式天生就具備「稽核」的能力,所有的「事件」都被保存下來,具備「重播事件」的能力,通常會跟 CQRS 與 Saga 模式搭配使用。

但,不方便的地方是「事件儲存量大」依據交易的不等,你的儲存媒體可能需要數十倍、數百倍以上的擴張。而且,完全依賴「重播」的機制來算出最終結果可能效能反應上也不佳,所以在處理上可能會建立一個當前狀態的「副本」,也就是 State Sourcing 跟 Event Sourcing 都存在的狀況。

再者,近期也有許多文章探討「事件的演進模式」,也就是隨著需求的改變事件本身可能也會改變,而 Event Sourcing 的模式又將所有的事件儲存下來。此時,你會考慮將前面所有的事件都改寫成新的,還是需要相容多版本的事件?這部分就必須在實施的時候進一步的研究業務情境來做決策。


Domain Event 服務間的鬆耦合協作

Domain Event 是一種表達「某件事已經發生」的訊號,通常以過去式命名,例如:OrderPlaced、PaymentCompleted。(Saga Choreography 的模式就是此原理的實作)。

Domain Event 的定義

  1. 具備業務語意(而不是技術事件)
    OrderPlaced(業務事件) vs RowInserted(技術事件)
  2. 跨 Bounded Context 傳遞
    幫助不同服務之間交換狀態
  3. 天然解耦
    發佈者不用關心誰會訂閱事件,該訂閱的自己就會訂閱

【範例】
假設今天我們在處理一個貸款的業務,那麼當一個使用者申請貸款的時候,會產生一個「貸款進件」的 Domain Event。接著,就會有審查系統訂閱此事件開始確認申請人的信用狀態,在審核完畢後也會發送一個「審核完畢」的事件讓後續其他服務接手,例如:貸款撥付跟貸款通知等。

一個事件可以由多個「訂閱者」進行後續的處理作業,是一個高度解耦的應用架構。

Domain Event 是微服務實現 事件驅動架構(EDA) 的基礎。它既是 DDD 的戰術設計工具,也是微服務協作的通道。


資料一致性四套件

模式|問題|場景|缺點
------ | ------ | ------ | ------ |
Saga|跨服務交易一致性|訂單、支付、庫存|複雜度高,需要補償交易
Aggregate|定義一致性邊界|訂單與訂單項目|邊界劃分錯誤會導致耦合
Event Sourcing|保存完整歷史|金融、稽核、IoT|儲存膨脹、查詢困難
Domain Event|服務間鬆散耦合|通知、報表|最終一致性、Debug 複雜

這些模式不是互斥的,而是可以 搭配使用:

  • Saga 常與 Domain Event 搭配,形成事件驅動的交易流程
  • Aggregate 幫助定義 Saga 的最小範圍
  • Event Sourcing 提供可回溯的事件來源,支援 CQRS

導入順序建議

  1. Aggregate 劃分服務邊界
    • 在戰術設計時,與領域專家討論 Aggregate Root
    • 避免過大或過小的 Aggregate
  2. 讓服務透過 Domain Event 溝通
  • 最容易導入,只要在完成某項工作的時候產生一個 Domain Event 即可。
  • 讓團隊開始思考「事件」的溝通模式是怎麼一回事。
  1. 接著考慮 Saga
    • 從高風險的跨服務接一開始 (例如:訂單 → 支付 → 出貨)
    • 先實作補償交易再考慮流程最佳化。
  2. 評估 Event Sourcing
    • 僅在需要稽核追蹤或高價值的場景使用
    • 先導入在局部服務,觀察儲存與查詢成本

結語

微服務架構下,資料一致性不再是單純的 ACID 問題,而是需要透過不同模式協同解決的挑戰。

  • Saga 幫我們保證跨服務交易的最終一致性
  • Aggregate 幫助劃定一致性邊界
  • Event Sourcing 保存完整事件流,讓我們能回溯歷史
  • Domain Event 讓服務之間以事件鬆耦合協作

這四個模式共同構築了微服務的「資料治理基石」,幫助我們在分散式系統的複雜環境中,依然能維持業務的穩定性與彈性


上一篇
微服務導入 – Day 15 微服務中的跨資料庫查詢
系列文
微服務導入:從觀念到落地的架構實戰地圖16
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言