總覽與定位
當單機儲存與寫入吞吐觸頂時,如何把資料拆到多台機器上?
隨著業務成長,單一資料庫節點遲早會遇到儲存容量、寫入吞吐或索引維護成本的上限。此時我們需要把資料集拆成多個子集,分散到不同節點上各自服務——這就是分片(Sharding / Partitioning)。
分片的核心問題只有一個:給定一筆資料(或查詢),應該路由到哪個 shard? 路由策略決定了擴容難度、查詢效率、熱點風險,以及跨 shard 交易的複雜度。
• 分片(Sharding):把不同資料子集放到不同節點,目的是擴充寫入與儲存容量。
• 複寫(Replication):把相同資料拷貝到多個節點,目的是容錯與擴充讀取吞吐。
Production 大規模系統(Cassandra、Spanner、DynamoDB)幾乎都是兩者結合:每個 shard 本身再有多份 replica。
| 維度 | 單機資料庫 | 分片後 |
|---|---|---|
| 儲存上限 | 受單機磁碟與索引大小限制 | 隨 shard 數線性擴展 |
| 寫入吞吐 | 單一 WAL / B-tree 寫入瓶頸 | 寫入分散到多個 shard owner |
| 查詢複雜度 | JOIN、聚合在單機完成 | 跨 shard 查詢需 scatter-gather 或 denormalize |
| 交易 | 本地 ACID 天然成立 | 跨 shard 交易需 2PC / Saga 等分散式協調 |
分片換來水平擴展能力,代價是路由、一致性與跨 shard 查詢的系統複雜度。
垂直 vs 水平分片
先釐清「拆欄位」與「拆列」——面試裡常被混用。
垂直分片(Vertical Partitioning)
依欄位或功能域拆分。例如把用戶表的 profile 欄位放到 Profile DB,把 billing 欄位放到 Billing DB;或把圖片、影片等大物件拆到 Object Storage,主表只留 metadata。
- 優點:各子表可獨立擴展、備份與存取控制;熱欄位與冷欄位可分流。
- 缺點:跨表 JOIN 變成跨服務 RPC;schema 變更需協調多個 store。
- 典型場景:微服務邊界、冷熱資料分離、合規隔離(PII 獨立庫)。
水平分片(Horizontal Partitioning / Sharding)
依列(row)拆分:同一 schema 的多筆資料,依 sharding key 路由到不同 shard。例如 user_id 模 4 分到 4 台 DB,或依時間 range 把訂單分到不同 partition。
- 優點:寫入與儲存可隨 shard 數近乎線性擴展;單 shard 資料量可控。
- 缺點:需選好 sharding key;跨 shard 查詢與交易成本高。
- 典型場景:社交 feed、電商訂單、IoT 時序資料、多租戶 SaaS。
MySQL 分表若只是把同一邏輯表拆成 orders_2024、orders_2025 但仍在一台機器上,那是分區(Partitioning)或表管理策略,不是水平擴展。真正的 sharding 意味著不同 partition 由不同節點服務。
三大分片策略
Range、Hash、Directory——路由公式決定擴容與查詢行為。
1. Range-based Sharding
依 sharding key 的連續區間劃分。例如用戶 ID 1..1M → Shard A,1M+1..2M → Shard B;或依時間 2024-01 → Partition Jan。
- 優點:範圍查詢(時間區間、ID 區間)可只打少數 shard;資料局部性佳,適合時序與報表。
- 缺點:新用戶或新時間段可能全部擠在「最新 range」→ hot shard;手動調整 range 邊界需 rebalancing。
2. Hash-based Sharding
對 sharding key 做 hash,再映射到 shard。最簡形式是 hash(key) % N(N 為 shard 數)。
- 優點:key 分布均勻時負載平衡佳;新增 key 自然打散。
- 缺點:N 改變時幾乎所有 key 需 remap(見一致性雜湊手冊);無法做 key 範圍查詢,只能 point lookup。
3. Directory / Lookup Sharding
維護一張路由表(shard map):tenant_id → shard_id 或 user_id → shard_id,由 control plane 或 metadata service 管理。
- 優點:彈性最高——可手動遷移大 tenant、做 canary、A/B 分 shard;不受 hash 公式限制。
- 缺點:路由表本身成為關鍵依賴與一致性挑戰;每次請求多一次 lookup(通常 cache)。
| 策略 | 路由方式 | 負載平衡 | 範圍查詢 | 擴容難度 |
|---|---|---|---|---|
| Range | key 落在哪個 interval | 易受 skew 影響 | 友好 | 需 split range、搬資料 |
| Hash | hash(key) % N 或 hash ring |
均勻(key 隨機時) | 不支援 | Modulo 全量 remap;Consistent Hash 局部 |
| Directory | 查 shard map | 可人工調整 | 取決於 map 設計 | 改 map + 背景遷移 |
沒有銀彈:Range 適合時序與報表;Hash 適合均勻 point lookup;Directory 適合多租戶與需人工調度的場景。
當 shard 數會動態變化時,單純 % N 代價過高。Production 常用 Consistent Hashing、Rendezvous Hashing 或 Dynamo-style 虛擬節點,把 remap 限制在局部區間——詳見本手冊「一致性雜湊綜合手冊」。
分片帶來的系統挑戰
Hot key、跨 shard 查詢、Rebalance——分片後才會浮現的問題。
選對 Sharding Key
Sharding key 應具備:高基數(避免全擠同一 shard)、查詢局部性(多數請求只需單 shard)、寫入分散(避免 sequential ID 全落最新 range)。
反例:用 country_code 做 key,大國流量會打爆單 shard;用 monotonic auto_increment 做 range sharding,新資料永遠寫入最後一個 partition。
Hot Spot(熱點)
即使 hash 均勻,單一 key 或少量 key 流量過大仍會打爆所在 shard(celebrity 貼文、搶購 SKU、全局 counter)。緩解手段包括:local cache、read replica fanout、key 拆分子 key、非同步聚合、寫入 queue 削峰。
跨 Shard 查詢與聚合
若查詢無法由 sharding key 定位單 shard,gateway 需scatter-gather:並行查所有 shard 再合併結果。成本高、延遲大,因此設計時常反規範化或建全域二級索引(如 Elasticsearch)承擔跨 shard 搜尋。
Rebalancing 與線上遷移
新增 shard、split hot range、遷移大 tenant 都需要背景搬資料。Production 流程通常包含:雙寫、追 incremental change、驗證、切流量、下線舊副本——並全程節流,避免搬遷與線上流量互搶 I/O。
若一筆交易涉及兩個 shard 上的列,本地 ACID 不再成立。需引入 2PC、Saga、或重新設計資料模型讓相關列共 shard(例如把 order 與 order_items 都用 order_id 做 sharding key)。
互動 Demo:分片路由模擬器
同一組 key,切換 Range 與 Hash 策略,觀察路由結果與 hot shard 差異。
下方模擬器有 4 個 shard(A–D)與 12 筆 sample key。切換策略後可看到每個 key 落在哪個 shard;Range 模式刻意模擬「新 key 集中在最新區間」造成的 skew,Hash 模式則展示較均勻的分布。
| Key | Sharding Key | 目標 Shard | 備註 |
|---|
洞察:Range 適合區間查詢但需防 skew;Hash 分散寫入但失去 range scan 能力——選型取決於存取模式而非公式優雅度。
面試考點與架構折衷
高頻追問:怎麼選 sharding key?怎麼擴容?跨 shard 怎麼查?
回答框架:
1. 列出主要存取模式(point lookup vs range scan vs 聚合)。
2. 選高基數、與查詢條件對齊的 key(如 messaging 用 conversation_id,電商用 user_id 或 order_id)。
3. 說明如何避免 hot spot(hash 子 key、local cache、異步 counter)。
4. 若需跨實體 JOIN,說明 co-location 或 denormalize 策略。
回答框架:
1. 若用 % N:幾乎全量 remap → 說明為何改用 Consistent Hashing 或 double-write 遷移。
2. 若用 Consistent Hashing:只搬相鄰 range,背景 backfill + 節流。
3. 若用 Directory:更新 shard map,雙寫 + 驗證 + 切流量。
4. 強調零 downtime需要 ring version / map version 與 client 相容窗口。
| 場景 | 建議策略 | 理由 |
|---|---|---|
| 多租戶 SaaS(大 tenant 需獨立遷移) | Directory + 必要時專用 shard | 可手動把 VIP tenant 搬到獨立節點 |
| 社交訊息 / 用戶資料 | Hash(user_id) 或 Consistent Hash |
Point lookup 為主,需均勻寫入 |
| 日誌 / 指標 / 時序 | Range by time | 範圍查詢與 TTL 刪除舊 partition 天然契合 |
| 電商訂單(依用戶查歷史) | Hash(user_id) |
同一用戶訂單共 shard,避免 scatter-gather |
在流量尚未觸頂前引入 sharding,會過早承擔路由、遷移與跨 shard 一致性成本。實務上常先垂直擴展 + 讀 replica + cache,確認單機瓶頸後再水平分片,並保留 rebalance 與 observability 預算。