分散式鍵值儲存系統#

鍵值儲存 (Key-Value Store) 對外只提供 get(key)put(key, value) 兩個操作,但要做成跨資料中心、永不停機的分散式系統,背後串接了本章前幾節的所有元件:一致性雜湊 做分片、複製做冗餘、Quorum 做一致性調節、向量時鐘解衝突、Gossip 偵測故障。本節以 Dynamo 風格的設計,把這些零件組成一個端到端的系統。

CAP / BASE / 一致性模型的理論細節見 分散式系統基礎,本節聚焦「怎麼把理論落成可運作的儲存」。

特性與單機限制#

  • 介面get(key) / put(key, value);key 唯一,value 可為任意 blob。
  • 效能取捨:短 key 較快;典型設計限制 value < 10 KB。
  • 單機限制:受記憶體與磁碟容量上限約束,大資料集必須分散到多台——這就是引入分散式設計的起點(呼應 方法論與容量估算 中「30 TB/天 ➡️ 必須分片」的推導)。

CAP 取捨:CP 還是 AP#

在網路分區發生時,鍵值儲存必須在一致性與可用性間二擇一:

選擇犧牲行為範例
CP可用性分區期間阻擋寫入以保證一致(如金融)ZooKeeper 類
AP一致性持續接受讀寫,可能回傳舊資料,分區復原後同步Dynamo / Cassandra

CA 系統在實務上不存在——網路分區無法避免,P 是必選項。Dynamo 風格的 KV 多半選 AP,再用 Quorum 與向量時鐘把一致性「調回來」。CAP 完整定義見 分散式系統基礎 — CAP 定理

整體架構#

flowchart TB
    Client(["Client"]) --> Coord["協調者節點<br/>Coordinator"]
    Coord --> Ring["一致性雜湊環<br/>(分片路由)"]
    Ring --> N1[("副本 1")]
    Ring --> N2[("副本 2")]
    Ring --> N3[("副本 3")]
    Gossip["Gossip<br/>成員與故障偵測"] -.-> N1 & N2 & N3

分區與複製#

  • 分區 (Partitioning):用 一致性雜湊 把 key 映射到環上,順時針找到負責節點。好處是自動擴展與異質性(容量大的節點分更多虛擬節點)。
  • 複製 (Replication):每個 key 複製到 N 個節點——從 key 的雜湊位置順時針取前 N 個不同實體節點(略過同一台的虛擬節點)。
    • 為容忍整個資料中心斷電,副本應跨資料中心放置。

一致性:Quorum#

設 N 為副本數、W 為寫入仲裁數、R 為讀取仲裁數。協調者寫入時等 W 個副本確認、讀取時等 R 個副本回應。

$$ W + R > N ;\Rightarrow; \text{強一致性} $$

因為讀寫集合必然至少有一個節點重疊,該節點持有最新資料。

配置 (N=3)特性
W=1, R=N寫快、讀慢
W=N, R=1讀快、寫慢
W=2, R=2平衡,且 2+2>3 ➡️ 強一致
W+R ≤ N無法保證強一致,可能讀到舊值

Quorum 讓一致性變成可調參數:同一套儲存能依業務需求在「讀優化」「寫優化」「強一致」間切換,不必重寫系統。這正是 BASE / 最終一致性的工程體現,見 分散式系統基礎 — BASE 理論

衝突解決:向量時鐘#

AP 系統允許併發寫入不同副本,會產生衝突版本。向量時鐘 (Vector Clock)[server, counter] 序對追蹤因果關係:

  • 寫到節點 Si 時,若已有 [Si, vi] 就遞增 vi,否則新增 [Si, 1]
  • 版本 X 是 Y 的祖先(無衝突):Y 在所有節點的 counter 都 ≥ X。
  • 兩版本衝突(互為 sibling):彼此在某節點的 counter 互有大小。
向量時鐘衝突範例
1. 寫 D1 (節點 Sx)            -> D1([Sx,1])
2. 讀 D1 改寫 D2 (Sx)         -> D2([Sx,2])          # D2 是 D1 後代
3. 讀 D2 改寫 D3 (Sy)         -> D3([Sx,2],[Sy,1])
4. 另一 client 讀 D2 改寫 D4 (Sz) -> D4([Sx,2],[Sz,1])
5. 讀到 D3 與 D4              -> 衝突! (Sy vs Sz 分歧)
6. client 解決後寫 D5 (Sx)   -> D5([Sx,3],[Sy,1],[Sz,1])

缺點:客戶端要實作衝突解決邏輯;序對可能膨脹,可設上限淘汰最舊項。向量時鐘屬分散式時間/因果序的應用,理論見 分散式系統基礎 — 一致性模型

故障處理#

故障類型機制
成員/失效偵測Gossip 協定:節點間互傳成員清單與心跳,去中心化偵測
暫時性故障寬鬆仲裁 (Sloppy Quorum) + 暗示移交 (Hinted Handoff):跳過離線節點選健康節點,恢復後把資料補回
永久性故障反熵 (Anti-entropy) + Merkle 樹:比對副本,只同步差異桶,同步量正比於差異而非總資料量
資料中心故障跨資料中心複製,容忍整個機房離線

讀寫路徑#

寫入路徑(LSM-tree 風格):

flowchart LR
    W["寫入請求"] --> CL["1. Commit Log<br/>(持久化)"]
    CL --> MT["2. Memtable<br/>(記憶體)"]
    MT -->|滿了 flush| SS["3. SSTable<br/>(磁碟, 有序)"]

讀取路徑:

  1. 先查記憶體快取(命中即回)。
  2. 未命中 ➡️ 用 Bloom filter 判斷 key 可能在哪些 SSTable,避免無謂的磁碟讀。
  3. 從候選 SSTable 取出,回傳結果。

Bloom filter 與 SSTable 的延遲假設來自 方法論 — 延遲數字:SSD 隨機讀約 150 µs、磁碟尋道約 10 ms,所以「先用 Bloom filter 過濾、再讀磁碟」能省下大量無效尋道。

小結#

目標採用技術
分散大資料集一致性雜湊
高可用多副本 + 跨資料中心複製
可調一致性Quorum (W + R > N)
衝突解決向量時鐘
增量擴展/異質一致性雜湊 + 虛擬節點
暫時故障寬鬆仲裁 + 暗示移交
永久故障Merkle 樹反熵
故障偵測Gossip 協定
快速讀寫Commit log + Memtable + SSTable + Bloom filter

鍵值儲存是本章的集大成案例:把 一致性雜湊、複製、Quorum、向量時鐘、Gossip 組裝起來,就得到一個可水平擴展、容錯、一致性可調的儲存系統——這也是理解 Dynamo、Cassandra 等實際產品的最短路徑。