Consistent Hashing: Rehashing Problem
CHAPTER 5: DESIGN CONSISTENT HASHING
Mục tiêu bài viết
- Hiểu vì sao phân phối key bằng
hash(key) % Nhoạt động tốt khi cụm server cố định. - Nhìn rõ “rehashing problem” khi thêm/bớt server trong cluster cache.
- Thấy được tác động thực tế: cache miss storm, tăng latency và tăng tải backend.
- Xây nền cho phần tiếp theo: consistent hashing để giảm tối đa lượng key phải di chuyển.
1) Context
Để scale ngang (horizontal scaling), ta cần phân phối dữ liệu/request đều lên nhiều server.
Cách đơn giản, phổ biến ban đầu:
\[serverIndex = hash(key) \bmod N\]Trong đó:
key: cache key cần tìmN: số lượng server trong pool
Cách này dễ implement, chi phí tính toán thấp, nhưng có một nhược điểm lớn khi số server thay đổi.
2) Kiến trúc tổng quan
Figure 5-1 — Phân phối key với công thức hash(key) % 4
Diagram (text-generated)
serverIndex = hash(key) % 4
Index 0: server0 <- key1, key3
Index 1: server1 <- key0, key4
Index 2: server2 <- key2, key6
Index 3: server3 <- key5, key7
Ví dụ bảng hash (Table 5-1) được dùng để map key -> server:
| key | hash | hash % 4 |
|---|---|---|
| key0 | 18358617 | 1 |
| key1 | 26143584 | 0 |
| key2 | 18131146 | 2 |
| key3 | 35863496 | 0 |
| key4 | 34085809 | 1 |
| key5 | 27581703 | 3 |
| key6 | 38164978 | 2 |
| key7 | 22530351 | 3 |
Khi hệ ổn định và N không đổi, dữ liệu thường phân phối tương đối đều.
3) Request/Data flow
Figure 5-2 — Khi server offline, N đổi từ 4 -> 3 và đa số key bị remap
Before: serverIndex = hash(key) % 4
After : serverIndex = hash(key) % 3
Old mapping (N=4):
- server0: key1, key3
- server1: key0, key4
- server2: key2, key6
- server3: key5, key7
New mapping (N=3):
- server0: key0, key1, key5, key7
- server1: key2, key4, key6
- server2: key3
Điểm mấu chốt: khi N đổi, không chỉ key trên server bị mất mới đổi chỗ, mà rất nhiều key khác cũng đổi server.
Flow tác động thực tế:
1) Server1 bị offline -> N giảm từ 4 xuống 3
2) Client vẫn dùng cùng hash(key), nhưng modulo thay đổi
3) Hàng loạt key trỏ sang server mới
4) Cache miss tăng đột biến
5) Backend DB bị dồn tải do nhiều cache misses cùng lúc
4) API / Data contract
Ví dụ API lookup cache key:
GET /api/v1/cache/lookup?key=key0
Ví dụ response:
{
"key": "key0",
"hash": 18358617,
"serverPoolSize": 4,
"serverIndex": 1,
"serverId": "server1",
"cacheHit": true
}
Khi server pool thay đổi (serverPoolSize: 3), cùng key có thể map sang server khác và cacheHit dễ chuyển thành false trong giai đoạn đầu.
5) Trade-offs
| Cách phân phối | Ưu điểm | Nhược điểm | Khi nào dùng |
|---|---|---|---|
hash(key) % N |
Dễ hiểu, dễ code, nhanh | Rehash lớn khi thêm/bớt server | Demo, hệ nhỏ, cluster ít thay đổi |
| Consistent hashing | Giảm mạnh số key remap khi topology đổi | Thiết kế phức tạp hơn, cần hash ring/virtual nodes | Hệ phân tán production, autoscaling thường xuyên |
Tại sao rehashing nguy hiểm:
- Tăng tỷ lệ miss -> tăng DB/QPS đột ngột
- Tăng tail latency (P95/P99)
- Dễ gây cascading failure nếu downstream yếu
6) Tóm tắt + bài học
hash(key) % Nphù hợp khi server pool ổn định, nhưng không chịu được thay đổi topology thường xuyên.- Rehashing problem là lý do chính consistent hashing ra đời.
- Mục tiêu của consistent hashing không phải “perfect balance tuyệt đối”, mà là:
- phân phối đủ đều,
- và di chuyển ít key nhất khi thêm/bớt node.
Ở bài tiếp theo của Chapter 5, mình sẽ đi vào hash ring và virtual nodes để giải bài toán này một cách thực dụng.