在分散式系統中,當多個獨立資料庫節點必須「要麼全部成功提交,要麼全部乾淨回滾」時,如何保證跨網路的原子性?

經典的解決方案是 兩階段提交協定(Two-Phase Commit, 2PC) 與其改良版 三階段提交協定(Three-Phase Commit, 3PC)。這兩大協定是 X/Open XA 分散式事務規範的理論基礎。

然而,在現代大規模互聯網與微服務環境下,2PC 與 3PC 卻因致命的同步阻塞(Synchronous Blocking)、協調者單點故障與網路分區腦裂而鮮少被直接用於高併發核心鏈路。

為了解決 2PC 鎖定資源過久的問題,工程界演化出了應用層的 TCC(Try-Confirm-Cancel) 模式。本文將全景拆解這三代強一致與業務補償協定的底層運作機制。


1. 兩階段提交(2PC):協定流程與致命瓶頸

2PC 由一個協調者(Coordinator) 與多個參與者(Participants / Resource Managers) 組成。

兩階段提交(2PC)準備與提交階段架構圖展示 Coordinator 在 Prepare 階段向參與者發送請求,全員 Yes 則發送 DoCommit,否則發送 DoAbort 回滾。階段一:準備階段 (Prepare Phase)Coordinator ── Prepare? ──► ParticipantsParticipants (A, B, C):• 執行本地 SQL、寫 Undo/Redo 日誌• 鎖定排他鎖 (持續持有直到 Phase 2!)➔ 投出 Yes 票 / No 票回傳 Coordinator階段二:提交階段 (Commit Phase)✅ 若全員投 Yes:Coordinator 發送 DoCommit ➔ 提交並釋放鎖❌ 若任一人投 No 或逾時:Coordinator 發送 DoAbort ➔ 全員 Rollback 釋放鎖

1.1 2PC 的三大致命缺陷

  1. 同步阻塞(Synchronous Blocking):
    • 參與者在第一階段投出 Yes 票後,會持續持有本地資料庫的行級排他鎖(Exclusive Locks)。
    • 在收到協調者的第二階段 DoCommit 之前,任何其他查詢或事務存取該行資料均會被死死卡住。在網路抖動時,鎖等待會迅速蔓延,引發全庫連線池枯竭。
  2. 協調者單點故障(Single Point of Failure, SPOF):
    • 若協調者在發送 Prepare 成功後、準備發送 DoCommit 的瞬間發生硬體當機,所有參與者將永遠陷入等待與鎖定狀態,無法自主決定是提交還是回滾。
  3. 網路分區引發資料不一致(腦裂):
    • 若協調者發送 DoCommit 時發生網路分區,只有部分參與者收到了 Commit 指令並提交,而未收到指令的參與者在超時後可能被迫回滾,導致整個分散式叢集狀態分裂。

2. 三階段提交(3PC):引入超時與預提交

為了緩解 2PC 的同步阻塞與單點當機問題,3PC 引入了逾時機制(Timeouts) 並將提交過程拆分為三段:

三階段提交(3PC)流程圖展示 3PC 透過 CanCommit 輕量詢問、PreCommit 預提交鎖定、DoCommit 正式提交三步驟減少阻塞。階段一: CanCommit輕量詢問 (不鎖定資源)階段二: PreCommit鎖定資源・寫日誌・參與者設逾時階段三: DoCommit正式提交・超時自動 Commit

2.1 3PC 如何解決阻塞?

  • 參與者自帶超時機制:在進入 PreCommit 階段後,若參與者在等待第三階段 DoCommit 時發生協調者當機或網路中斷,參與者在等待超時後會自動預設執行 Commit!
  • 理論缺陷:若協調者原先決定發送 Abort,但因網路分區只有部分節點收到 Abort,其他超時節點自作主張執行了 Commit,依然會導致嚴重的資料不一致。因此 3PC 在實際生產中極少被原生部署。

3. 業務層的 2PC:TCC 模式(Try-Confirm-Cancel)

為了解除底層資料庫層面的長週期行鎖,工程界將 2PC 的理念上移至應用業務層,形成了 TCC 模式:

階段業務行為與責任
1. Try (預留資源)完成業務檢查,預留/凍結必要的業務資源 (如: 凍結餘額 100 元)
2. Confirm (確認)真正執行業務操作,直接使用 Try 階段已凍結的資源 (不進行二次檢查)
3. Cancel (取消)釋放 Try 階段凍結的預留資源,恢復原始狀態

3.1 TCC 轉帳案例深度拆解

假設從帳戶 A 向帳戶 B 轉帳 100 元:

傳統 2PC 長期行鎖 vs TCC 業務資源預留架構對比展示傳統 2PC 跨服務長週期鎖定行記錄,而 TCC 透過 Try 凍結預留資源使底層事務立即提交釋放鎖。❌ 傳統 2PC (資料庫層死鎖隱患):UPDATE account SET balance = balance - 100 WHERE id = ‘A’; (持續長週期鎖定 A 行記錄直到全局 Commit)✅ TCC 模式 (業務資源預留・底層事務秒級釋放):1. Try 階段:帳戶 A frozen_balance += 100 ➔ 成功預留 100 元,底層事務立即 Commit 釋放行鎖!2. Confirm 階段 (全員 Try 成功):帳戶 A 正式扣減凍結金額,帳戶 B balance += 100 正式入帳3. Cancel 階段 (任一 Try 失敗):帳戶 A frozen_balance -= 100 (解凍資金,完全無鎖回退)

3.2 TCC 實踐必須防禦的三大異常

  1. 空回滾(Empty Rollback):
    • 網路延遲導致某服務的 Try 請求根本未抵達,而協調者已觸發回滾發送了 Cancel。
    • 防禦:Cancel 必須先檢查是否存在對應的 Try 記錄,若無則標記為空回滾,不做任何資金釋放。
  2. 防懸掛(Anti-Suspension):
    • 空回滾完成後,原本迷路的 Try 請求此時突然延遲抵達。
    • 防禦:Try 執行前必須檢查是否已存在 Cancel 記錄,若已取消則直接丟棄該請求。
  3. 冪等性(Idempotency):
    • Confirm 與 Cancel 可能因網路重試被多次執行,必須透過全域唯一事務 ID 保證重複呼叫無副作用。

4. 分散式事務技術選型全景矩陣

維度2PC (XA 規範)TCC 模式Saga 模式
一致性級別強一致性 (ACID)最終一致性最終一致性
資源鎖定時間極長 (直到 Commit)極短 (本地立即提交)極短 (本地立即提交)
程式碼侵入性零 (資料庫層支援)極高 (需寫 3 個介面)中等 (需寫補償介面)
系統吞吐量極低極高極高
適用場景內部極短跨庫交易金融核心扣款/支付跨服務訂單履約長流程