本章涵蓋三個分散式系統設計模式:租約(Lease)提示移交(Hinted Handoff)讀取修復(Read Repair)


租約(Lease)#

背景#

在分散式系統中,客戶端經常需要取得特定資源的指定權限。例如,客戶端可能需要對某個檔案的獨佔寫入權限(Exclusive Write Access)。實現此需求的一種方式是透過分散式鎖定(Distributed Locking):客戶端先取得與檔案關聯的獨佔鎖,然後才進行檔案更新。

然而,鎖定機制存在一個根本問題:鎖一旦授予,會一直持有直到客戶端明確釋放為止。如果客戶端因為任何原因無法釋放鎖——例如程序崩潰(Process Crash)、死結(Deadlock)或軟體缺陷(Bug)——該資源將被無限期鎖定,導致資源無法使用,直到系統重置為止。

分散式鎖定的最大風險在於:當持有鎖的客戶端故障時,鎖無法自動釋放,造成資源永久不可用。

定義#

使用有時間限制的租約(Time-bound Lease) 來授予客戶端對資源的權限。

解決方案#

租約(Lease) 類似於鎖,但即使客戶端離線也能正常運作。其運作機制如下:

  • 客戶端向系統請求一個有限時間的租約
  • 租約到期後會自動失效,無需客戶端主動釋放
  • 如果客戶端希望延長租約,可以在租約到期前進行續約(Renew)

租約與鎖的關鍵差異在於:租約有內建的過期機制,不依賴客戶端主動釋放,因此能有效避免資源被永久鎖定的問題。

實際應用#

  • Chubby:客戶端與領導者(Leader)維持一個有時間限制的會話租約(Session Lease)。在租約有效期間內,領導者保證不會單方面終止該會話。

提示移交(Hinted Handoff)#

背景#

根據一致性級別的不同,分散式系統在某些節點故障時仍然可以處理寫入請求。例如,假設系統的複製因子(Replication Factor)為 3,且使用法定人數一致性(Quorum Consistency),那麼即使一個節點當機,系統仍可將資料寫入其餘兩個節點。

但問題是:當故障節點恢復上線後,如何將它錯過的資料寫入該節點?

定義#

對於故障的節點,系統保留所有錯過的寫入請求的提示記錄(Hint)。一旦故障節點恢復,系統根據儲存的提示將寫入請求轉發給該節點。

解決方案#

當目標節點故障時,協調節點(Coordinating Node) 會執行以下步驟:

  • 提示(Hint) 寫入本地磁碟
  • 提示中包含完整的資料內容,以及該資料原本應屬於哪個節點的資訊
  • 當目標節點恢復上線後,協調節點將提示中的資料轉發給它
sequenceDiagram
    participant C as 用戶端(Client)
    participant Co as 協調節點(Coordinator)
    participant HS as 提示儲存(Hint Store)
    participant B as 節點B(Node B)

    C->>Co: 1. 寫入請求(目標為節點B)
    Co->>B: 嘗試寫入
    B--xCo: 節點B 無回應(故障中)
    Co->>HS: 2. 儲存提示記錄(Hint)\n包含完整資料與目標節點資訊
    Co-->>C: 確認寫入(其他副本已成功)

    Note over B: 節點B 恢復上線
    HS->>HS: 3. 偵測到節點B 已恢復
    HS->>B: 4. 重播提示資料(Replay Hint Data)
    B-->>HS: 確認接收
    HS->>HS: 5. 刪除已完成的提示記錄

提示移交確保了系統在節點故障期間不會遺失寫入操作。故障節點恢復後,能夠透過提示記錄補齊所有錯過的資料更新。

實際應用#

  • Cassandra:節點使用提示移交(Hinted Handoff)來記住故障節點錯過的寫入操作,確保節點恢復後資料能夠同步。
  • Dynamo:透過結合提示移交和寬鬆法定人數(Sloppy Quorum),實現「永遠可寫入(Always-Writeable)」的設計目標——即使部分節點不可用,系統仍能接受寫入請求。

讀取修復(Read Repair)#

背景#

在資料被複製到多個節點的分散式系統中,某些節點可能因為錯過了寫入或更新請求而持有過時的資料(Stale Data)。這種資料不一致可能長期存在,直到有機制主動修復為止。

定義#

讀取操作期間修復過時資料:從多個節點讀取資料,進行比較,並將較新版本推送到持有過時資料的節點。

解決方案#

基於法定人數(Quorum)機制,系統在讀取時會從多個節點獲取資料。具體流程如下:

  1. 摘要比對(Digest Comparison):假設 Quorum = 2,系統從一個節點讀取完整資料,從第二個節點讀取摘要(Digest / Checksum)
  2. 不一致檢測:如果摘要不匹配,表示資料存在不一致,系統會從所有副本(Replica) 讀取完整資料,找出最新版本
  3. 回傳與修復:將最新資料回傳給客戶端,同時啟動讀取修復(Read Repair) 流程,將最新版本推送到持有過時資料的節點
flowchart TD
    Start([用戶端發送讀取請求]) --> Send[協調節點向多個副本\n發送讀取請求(Read Request)]
    Send --> Receive[接收各副本的回應]
    Receive --> Compare{比較回應內容\n是否一致?}
    Compare -->|一致| Return1([回傳資料給用戶端])
    Compare -->|不一致| FindLatest[識別最新版本\nIdentify Most Recent Version]
    FindLatest --> Return2[回傳最新資料給用戶端]
    Return2 --> Repair[背景執行讀取修復\nBackground Read Repair]
    Repair --> Push[將最新版本推送到\n持有過時資料的副本]
    Push --> Done([修復完成])

當讀取一致性級別低於「All」時,某些系統會以機率性方式(Probabilistic Read Repair) 執行讀取修復。例如,僅對 10% 的讀取請求進行修復檢查,以在資料一致性與系統效能之間取得平衡。

實際應用#

  • Cassandra:使用讀取修復(Read Repair)確保副本之間的資料一致性。
  • Dynamo:同樣採用讀取修復機制,在讀取過程中自動修正過時的副本資料。