簡介
當資料庫膨脹到數百GB或TB時,單一伺服器無法處理。 分片將資料分割成較小的部分,每個部分位於單獨的伺服器上。
1. 分區與分片
Partitioning: Chia data TRONG 1 database server
┌─────────────────────────────────────┐
│ Server (1 máy) │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │Part 1│ │Part 2│ │Part 3│ │
│ │Jan │ │Feb │ │Mar │ │
│ └──────┘ └──────┘ └──────┘ │
└─────────────────────────────────────┘
Sharding: Chia data GIỮA nhiều servers
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Server 1 │ │ Server 2 │ │ Server 3 │
│ Shard A │ │ Shard B │ │ Shard C │
│ User 1-M │ │ User M-N │ │ User N-Z │
└──────────┘ └──────────┘ └──────────┘
2. 垂直分割區與水平分割區
2.1 垂直分割區
-- Trước: 1 table lớn
users (id, name, email, avatar_blob, bio_text, settings_json, ...)
-- Sau: Tách theo columns
users_core (id, name, email) -- Hot data, truy vấn thường
users_profile (id, avatar_blob, bio) -- Large data, ít truy vấn
users_settings(id, settings_json) -- Read-heavy, cache được
2.2 水平分區(分片)
-- Trước: 1 table 100M rows
orders (id, user_id, product_id, amount, created_at)
-- Sau: Chia theo rows
orders_shard_0: user_id % 4 == 0 (25M rows)
orders_shard_1: user_id % 4 == 1 (25M rows)
orders_shard_2: user_id % 4 == 2 (25M rows)
orders_shard_3: user_id % 4 == 3 (25M rows)
3. 分片策略
3.1 基於範圍的分片
Shard Key: created_at
Shard 1: 2024-01 → 2024-03
Shard 2: 2024-04 → 2024-06
Shard 3: 2024-07 → 2024-09
Shard 4: 2024-10 → 2024-12
Ưu điểm:
✅ Range queries hiệu quả
✅ Dễ thêm shard mới
Nhược điểm:
❌ Hot spots (shard mới nhất nhận nhiều writes)
❌ Data không đều
3.2 基於哈希的分片
Shard Key: user_id
Hash Function: user_id % N (N = số shards)
user_id=101 → 101 % 4 = 1 → Shard 1
user_id=202 → 202 % 4 = 2 → Shard 2
user_id=303 → 303 % 4 = 3 → Shard 3
user_id=404 → 404 % 4 = 0 → Shard 0
Ưu điểm:
✅ Data phân bố đều
✅ Không có hot spots
Nhược điểm:
❌ Range queries phải query ALL shards
❌ Thêm shard → Phải rehash tất cả data!
3.3 一致性哈希
Vấn đề: Hash-based với N shards, thêm 1 shard → rehash tất cả
Giải pháp: Consistent Hashing Ring
Shard A (0°)
│
┌───────┼───────┐
│ │ │
Shard D Ring Shard B
(270°) (hash) (90°)
│ │ │
└───────┼───────┘
│
Shard C (180°)
Key → hash → vị trí trên ring → đi clockwise → gặp shard nào thì vào shard đó
Thêm Shard E (45°):
- Chỉ di chuyển data giữa 0° và 45°
- Không ảnh hưởng data khác
- Di chuyển ~1/N data thay vì tất cả
3.4 以目錄為基礎的分片
┌────────────────────────────────────────┐
│ Lookup Service / Table │
│ ┌──────────────────────────────────┐ │
│ │ user_id: 1-1000 → Shard A │ │
│ │ user_id: 1001-5000→ Shard B │ │
│ │ user_id: VIP → Shard C │ │
│ │ user_id: 5001+ → Shard D │ │
│ └──────────────────────────────────┘ │
└────────────────────────────────────────┘
Ưu điểm:
✅ Flexible: thay đổi mapping dễ dàng
✅ Có thể balance thủ công
Nhược điểm:
❌ Lookup service = SPOF
❌ Extra hop cho mọi query
4.選擇分片鍵
Shard Key tốt:
✅ Cardinality cao (nhiều unique values)
✅ Phân bố đều (không hot spots)
✅ Phù hợp query patterns
✅ Immutable (không thay đổi)
Ví dụ hệ thống E-commerce:
❌ country_code → VN chiếm 80% traffic → hot spot
❌ created_at → Shard mới nhất quá tải
✅ user_id → Phân bố đều, query theo user phổ biến
✅ order_id → UUID, phân bố tốt
Ví dụ hệ thống Chat:
❌ user_id → Group chat phải query nhiều shards
✅ room_id → Messages cùng room → cùng shard
5. 分片問題
5.1 跨分片查詢
-- Query đơn giản (single shard):
SELECT * FROM orders WHERE user_id = 123;
→ hash(123) → Shard 2 → Query 1 shard ✅
-- Cross-shard query:
SELECT * FROM orders ORDER BY created_at DESC LIMIT 20;
→ Phải query TẤT CẢ shards
→ Merge + Sort kết quả
→ Chậm hơn nhiều ❌
5.2 跨分片連接
-- Trước sharding (1 database):
SELECT u.name, o.amount
FROM users u JOIN orders o ON u.id = o.user_id;
-- Sau sharding:
-- users ở Shard theo user_id
-- orders ở Shard theo order_id (khác shard!)
-- JOIN phải đi qua network → Rất chậm
Giải pháp:
1. Denormalization: Copy user.name vào orders table
2. Cùng shard key: Shard cả users và orders theo user_id
3. Application-level join: Query riêng, merge trong code
5.3 分散式事務
Vấn đề: Transfer $100 from User A (Shard 1) to User B (Shard 2)
Shard 1: balance -= 100
Shard 2: balance += 100
→ Phải ATOMIC! Cả 2 phải thành công hoặc cả 2 fail
Giải pháp: Two-Phase Commit (2PC)
Phase 1 (Prepare):
Coordinator → Shard 1: "Prepare to debit $100"
Coordinator → Shard 2: "Prepare to credit $100"
Both respond: "Ready"
Phase 2 (Commit):
Coordinator → Shard 1: "Commit"
Coordinator → Shard 2: "Commit"
Thay thế: Saga Pattern (eventual consistency)
Step 1: Debit User A
Step 2: Credit User B
Compensate: If Step 2 fails → Refund User A
6. 重新分片
Khi nào cần re-shard:
- Shard quá lớn (disk/memory/CPU)
- Data phân bố không đều (hot shard)
- Thêm capacity
Strategies:
1. Double shard count (4 → 8):
Mỗi shard chia đôi, di chuyển 50% data
2. Virtual shards:
Tạo nhiều virtual shards hơn physical servers
Khi thêm server → Move virtual shards
3. Online re-sharding:
a) Tạo shard mới
b) Dual-write (ghi cả old + new)
c) Backfill data cũ sang shard mới
d) Switch reads sang shard mới
e) Stop writing to old shard
對比總結
| 戰略 | 資料分發 | 範圍查詢 | 新增/刪除碎片 | 複雜性 |
|---|---|---|---|---|
| 範圍 | 可能會出現偏差 | 好 | 簡單 | 低 |
| 哈希 | 全部 | 可憐 | 難(重述) | 平均 |
| 一致性哈希 | 全部 | 可憐 | 簡單(資料移動較少) | 曹 |
| 目錄 | 自訂 | 自訂映射 | 靈活 | 曹 |
練習
-
分片鍵選擇: 擁有 1 億用戶的社群媒體系統,功能:使用者個人資料、貼文、留言、按讚。為每個表選擇分片鍵並解釋。
-
一致性雜湊: 畫一個有4個節點的一致性雜湊環,加入第5個節點。計算需要移動的資料的百分比。
-
重新分片計畫: 你有 4 個分片,分片 2 佔數據的 60%(熱點是因為隨著時間的推移基於範圍)。編寫零停機時間的重新分片計劃。