一致性雜湊 (Consistent Hashing)

為什麼需要 Consistent Hashing

分散式系統常把資料分散到多台節點上。最直觀作法是 簡單模數雜湊

server = hash(key) % N     # N = 節點數

簡單 hash 的致命缺陷

當 N 改變(加入或移除節點),幾乎所有 key 的位置都會變動

N key → node 對應
N = 3 1,4,7→N1; 2,5,8→N2; 3,6,9→N0
N = 4 1,5,9→N1; 2,6→N2; 3,7→N3; 4,8→N0
結果 9 個 key 有 7 個要搬(只剩 1、2 不動)— 大量搬遷
後果

大規模重新分配 → 暫時效能崩塌、快取全 miss、系統不穩定

Consistent Hashing 的核心價值

節點數變動時,只搬動一小部分資料,其他 key 保留在原節點。


運作原理

(a) Hash Ring(雜湊環)

把所有可能的 hash 值映射到一個圓環上(0 → MAX_HASH)。

                  0 / MAX
                   ▲
                   │
      D(900) ●─────┼─────● A(250)
              \    │    /
               \   │   /
         順時針 \  │  /
                \ │ /
                 \│/
      C(750) ●────┼────● B(500)
                  │
               (假設 hash=200 → 順時針碰到 A → 存 A)
               (假設 hash=400 → 順時針碰到 B → 存 B)

(b) 新節點加入

假設新節點 E 落在 150
→ 只有「D(900) 與 E(150) 之間」的 key(0~150, 900~1024)
  需從 A 搬到 E
→ 其餘資料完全不動

(c) 節點移除

假設 A(250) 下線
→ 原屬 A 的 key 順時針移到下一個節點 B(500)
→ 其他節點不受影響

Virtual Nodes(虛擬節點)

為什麼需要

基本版的 Consistent Hashing 有兩個問題:

問題 說明
資料分佈不均 節點少時 hash 環上位置可能集中,某些節點吃到一半以上的流量
忽略硬體差異 強機和弱機都只拿到一個區間,沒辦法「按能力分配」

例如移除節點 A 後,下游節點 B 要獨自扛下 A 的所有 key → 負載翻倍。

vNodes 做法

每個實體節點對應到 多個虛擬節點,分散在環上:

Physical Nodes  →  Virtual Nodes on Ring
A                   A1(250), A2(580), A3(920)
B                   B1(500), B2(830), B3(80)
C                   C1(750), C2(160), C3(420)
D                   D1(1024), D2(330), D3(660)

vNodes 的好處

好處 機制
分佈更均勻 每個節點有多個隨機位置,分散到整個環上
按能力分配 強機多放 vNodes(如 50 個),弱機少放(如 20 個)
搬遷粒度細 節點變動時影響的 vNode 是多個小區段 → 負載變化更平滑

演算法複雜度

操作 複雜度(N=節點數, V=每節點 vNodes 數)
查詢某 key 落點 O(log(N·V))(環上二分搜)
新增節點 O(V·log(N·V))
移除節點 O(V·log(N·V))
搬遷資料量 O(K/N)(K=總 key 數)而非 O(K)

Simplification-with-exceptions

邊界情況

  • 並非所有分散式系統都用 consistent hashing — 例如 Elasticsearch 用
    hash(shard_key) % num_shards 配合 shard 總數不常改,反而沒有環結構。
  • Jump Hash / Rendezvous Hash 是較新的替代方案,記憶體佔用更低;但
    consistent hashing 仍是面試常見答案。
  • Hot key 問題 — 若單一 key 本身流量極大,換節點也救不了;需額外做 key-level
    replication 或快取前置。
  • Virtual Nodes 數量要取平衡 — 太少分佈不均;太多 routing table 大、查找
    變慢(典型設定每節點 100~200 個 vNode)。


在 System Design Interview 的應用

記憶口訣

變動的節點 + 需要穩定歸屬 + 想少搬家」 → 用 consistent hashing

常見觸發場景

場景 說明
Distributed Cache Memcached / Redis 分片,避免 key % N 帶來的大規模失效
Storage Sharding Cassandra、DynamoDB 的 partition routing
Sticky Connections 聊天室 / 即時服務,同 user 或 room 路由到固定節點
API Gateway / Session 減少跨節點 session 同步
Rate Limiting user_id / api_key 穩定分到對應節點做限流統計
Metrics / Aggregation (user_id, feature) 聚到同節點做累加
CDN / Edge Routing URL / 內容 ID 穩定映射到 edge 節點做快取

與其他概念的串連

流量大 → 需要 Horizontal Scaling(加節點)
      → 資料要分片到多節點(Sharding)
      → 節點會變動(擴縮容、故障)
      → 用 Consistent Hashing 讓搬遷最小化
      → vNodes 讓分佈更均勻