分片 (Partitioning / Sharding)

★★★★★Draft

FromDDIA

📚 From the Books

分片 (Partitioning / Sharding)ConceptData Distribution

當資料量或查詢吞吐超過單節點負荷,就把資料拆成子集分散到多台機器。目標是讓資料與負載均勻分佈、避免熱點 (hot spot)。分片與複製通常搭配使用——每筆資料屬於一個分片,該分片再複製到多個節點以容錯。

🧠 Core Ideas

TIP

兩種基本分片策略,是「範圍查詢」與「負載均勻」之間的取捨:按鍵範圍保留排序、範圍掃描快,但容易熱點;按雜湊值打散得均勻,但失去範圍查詢。Cassandra 的複合主鍵是折衷——第一段雜湊決定分片,其餘段在分片內排序。

⚖️ 次要索引與分片

主鍵分片很單純,麻煩的是次要索引(查「所有紅色的車」這種)無法自然對齊分片結構:

按文件分片(本地索引)— 寫入快、讀取 scatter/gather
  • 每個分片各自維護只涵蓋自己文件的索引,寫入只更新該分片 → 本地索引
  • 讀取麻煩:目標值可能散在任何分片,得向所有分片查再彙整= scatter/gather,受尾端延遲放大影響。
  • 實務最常見:MongoDB、Cassandra、Elasticsearch、SolrCloud 都用這套。
按詞彙分片(全域索引)— 讀取快、寫入慢且複雜
  • 建跨所有分片的全域索引,索引本身也分片,但依「詞彙」而非主鍵分。
  • 讀取只查含目標詞彙的那個索引分片,免 scatter/gather。
  • 但一筆文件的多個詞彙可能落在不同索引分片 → 寫入要更新多個分片,通常非同步(如 DynamoDB 全域次要索引)。

⚖️ 重新平衡 (Rebalancing)

節點增減、資料成長時要搬資料。原則:搬完負載公平、過程中持續讀寫、搬動量盡可能少

錯誤示範:hash mod N
  • 直覺想用 hash(key) mod N,但 N 一改,幾乎所有鍵都要搬。完全不可行。
  • (這正是一致性雜湊要解決的問題。)
固定分片數 — 分片數不變,只改分片到節點的分配
  • 一開始建遠多於節點的分片(如 10 節點建 1000 分片),每節點分一批。
  • 加節點就從現有節點「偷」幾個分片;鍵到分片的對應不變。Riak、Elasticsearch、Couchbase 用。
  • 挑戰:初始化就得選好分片數,太少限制擴展、太多管理開銷大。
動態分片 — 分片隨資料量自動分裂 / 合併
  • 分片超過閾值(HBase 預設 10 GB)自動分裂,縮小則與相鄰合併
  • 適合按鍵範圍。空庫只有一個分片會集中寫 → 用預分片 (pre-splitting) 解。
按節點比例分片 — 每節點固定數量分片
  • Cassandra 預設每節點 256 分片。加節點時隨機分裂現有分片、取走一半。
  • 需搭配雜湊分片(分裂邊界從雜湊範圍隨機挑)。

WARNING

全自動重新平衡 + 自動故障偵測很危險:某節點暫時過載回應慢,被誤判失效而觸發再平衡,反而把更多負載壓上去 → 連鎖故障。讓人參與決策(半自動)是有價值的。

⚖️ 請求路由 (Service Discovery)

資料分散後,客戶端怎麼知道連哪個節點?三種做法:

三種路由方式
  • 任意節點轉發:客戶端連任一節點,命中就處理、否則轉發(Cassandra / Riak 用 gossip protocol)。
  • 路由層:請求先過 routing tier 做分片感知的負載平衡(MongoDB 的 mongos)。
  • 客戶端感知:客戶端自備分片→節點對應,直連正確節點。
  • 三者共同難題:對應關係變化時,誰、如何得知?許多系統用 ZooKeeper 維護權威對應並通知訂閱者(HBase、SolrCloud、Kafka)。

🔑 Takeaways

✍️ My Notes

No notes yet — jot your takeaways or Q&A here.

📖 Further Reading

🔗 Dive Deeper