Replication, Sentinel và Cluster: Redis "partition" thế nào
Ok, vậy Redis có gì giống partition bên Kafka không?
Có. Khái niệm gần nhất là sharding trong Redis Cluster: Redis chia key space thành 16384 hash slots. Nhưng không nên coi Kafka partition = Redis hash slot hoàn toàn. Giống ở ý tưởng chia dữ liệu ra nhiều phần, khác ở mục đích. Để hiểu đủ, đi từ một node lên ba tầng: replication → Sentinel → Cluster.
1. Bài toán
shop-app ──> Redis (1 node, 8 GB)
cache product, session, rate limit, lock
Hai rủi ro: node chết thì mọi người bị logout và DB nhận toàn bộ tải (avalanche, bài 7.2); dữ liệu tăng vượt RAM một máy.
2. Vấn đề
- Availability: một node là single point of failure.
- Scale đọc: một node chỉ có từng ấy CPU cho main thread.
- Scale dữ liệu và ghi: RAM một máy có hạn.
3. Giải pháp: ba tầng
| Tầng | Giải quyết | Không giải quyết |
|---|---|---|
| Replication (master + replica) | Copy dữ liệu, scale đọc | Tự failover |
| Sentinel | Theo dõi master, tự promote replica, báo client master mới | Dữ liệu lớn hơn một máy |
| Cluster | Sharding qua nhiều master + failover tích hợp | Lệnh multi-key khác slot |
Replication là async: master trả OK cho client trước, rồi mới gửi sang replica. Master chết trước khi gửi thì write đó mất. WAIT numreplicas timeout giúp chờ replica nhận, nhưng vẫn không biến Redis thành strongly consistent.
Cluster chia key:
slot = CRC16(key) mod 16384
Master A: slot 0 – 5460 ── Replica A'
Master B: slot 5461 – 10922 ── Replica B'
Master C: slot 10923 – 16383 ── Replica C'
product:100 → CRC16 → slot 8000 → Master B
Hash tag: chỉ phần trong {...} được hash. cart:{42} và session:{42} cùng slot, nên dùng chung trong Lua script hay MULTI được.
4. Code từng bước
Bước 1: Sentinel (dữ liệu vừa một máy, cần HA):
spring:
data:
redis:
password: ${REDIS_PASSWORD}
sentinel:
master: shop-master
nodes: sentinel-1:26379,sentinel-2:26379,sentinel-3:26379
Bước 2: Cluster (cần sharding):
spring:
data:
redis:
password: ${REDIS_PASSWORD}
cluster:
nodes: redis-1:6379,redis-2:6379,redis-3:6379
max-redirects: 3
lettuce:
cluster:
refresh:
adaptive: true # cập nhật topology khi gặp MOVED / failover
period: 30s
Bước 3: Java: key cần đi chung thì dùng hash tag; đọc từ replica nếu chấp nhận stale:
@Bean
LettuceClientConfigurationBuilderCustomizer readFromReplica() {
return b -> b.readFrom(ReadFrom.REPLICA_PREFERRED); // cache đọc nhiều
}
// Hai key cùng user nằm cùng slot nhờ {userId}
String cartKey = "cart:{" + userId + "}";
String lastSeenKey = "recent:{" + userId + "}";
Bước 4: Test
redis-cli -c -h redis-1 CLUSTER KEYSLOT product:100 # 8000 (ví dụ)
redis-cli -h redis-1 GET product:100 # (error) MOVED 8000 redis-2:6379
redis-cli -c -h redis-1 GET product:100 # -c tự theo MOVED
redis-cli -c MGET product:1 product:2 # CROSSSLOT nếu khác slot
5. Cách hoạt động: failover
Sentinel 1 Sentinel 2 Sentinel 3
\ | /
ping master mỗi giây
master không trả lời > down-after-milliseconds
→ SDOWN (một sentinel thấy)
→ ODOWN (đủ quorum đồng ý)
→ bầu leader sentinel → promote replica tốt nhất
→ replica khác chuyển sang master mới
→ client hỏi sentinel, kết nối master mới
Cluster làm tương tự nhưng không cần Sentinel: các master gossip với nhau, đa số master đánh dấu một master là FAIL thì replica của nó được promote.
6. So sánh với Kafka
| Concept | Kafka | Redis Cluster |
|---|---|---|
| Chia dữ liệu | Partition | Hash slot |
| Đơn vị dữ liệu | Record/message | Key |
| Chọn phần | hash(message key) mod số partition | CRC16(key) mod 16384 |
| Server | Broker | Redis node |
| Bản sao | Replica (ISR) | Replica (async) |
| Consumer parallelism, ordering | Có: partition → consumer trong group | Không có khái niệm này |
7. Khi nào nên dùng / không nên dùng
- Một node + replica: dev, hệ thống nhỏ, chỉ cache.
- Sentinel: dữ liệu vừa một máy, cần tự failover. Đa số shop-app cỡ vừa dừng ở đây.
- Cluster: dữ liệu hoặc write throughput vượt một máy. Đổi lại: lệnh multi-key phải cùng slot, chỉ có database 0, client phải hỗ trợ cluster.
- Cloud managed (ElastiCache, Azure Cache for Redis) làm sẵn các phần này.
Vậy chung quy lại:
- Redis có sharding và single thread để thực thi command;
- Kafka có partition, topic, consumer group;
- RabbitMQ thì exchange và queue.
Mình hiểu vậy đúng không?
Đúng, ở mức interview bạn có thể đóng khung như vậy. Chỉnh một chút cho chính xác:
| Công nghệ | Concept nên nhớ |
|---|---|
| Redis | Key-value, TTL, data types, hash slot/sharding, replica, thực thi command chủ yếu trên một thread |
| Kafka | Producer, topic → partition, offset, consumer group, broker, replica |
| RabbitMQ | Producer → exchange → queue → consumer → ACK, routing key |
Redis: Key → Hash slot → Node → main thread thực thi
Kafka: Producer → Topic → Partition (offset) → Consumer group
RabbitMQ: Producer → Exchange → (routing) → Queue → Consumer → ACK
Lưu ý: single thread là cách Redis thực thi command trên mỗi node. Cluster 3 master là 3 main thread độc lập; atomic chỉ được đảm bảo trong một node, đó là lý do multi-key phải cùng slot.
Khi master chết và replica được promote, lock hay cache đang nằm trên master cũ có bị ảnh hưởng không?
Có, vì replication async. Những write master đã trả OK nhưng chưa kịp sang replica sẽ mất:
t1 Job instance A: SET lock:report token-A NX PX 30000 → OK (master)
t2 master chết trước khi replicate
t3 replica promote, không có lock:report
t4 Job instance B: SET lock:report token-B NX PX 30000 → OK
→ A và B cùng chạy job
- Cache: mất vài key mới set → miss → load lại DB. Chấp nhận được.
- Rate limit counter: đếm lại một chút. Chấp nhận được.
- Session: vài session vừa tạo bị mất, user đăng nhập lại.
- Lock: hai bên cùng giữ lock. Đây là chỗ nguy hiểm, bài 7.5 bàn cách dùng fencing token và ràng buộc DB.
Thêm nữa: trong lúc failover (thường vài giây đến chục giây) write bị lỗi. App cần timeout ngắn, retry có giới hạn, và fallback (cache lỗi thì đọc DB, có circuit breaker).
Phỏng vấn hỏi Redis HA, Sentinel và Cluster khác nhau thế nào thì trả lời sao?
Q1. Sentinel và Cluster khác nhau thế nào?
🇻🇳 Tiếng Việt:
Sentinel dùng cho mô hình một master nhiều replica: nó theo dõi master, khi master chết thì promote replica và báo client địa chỉ mới. Toàn bộ dữ liệu vẫn nằm trên một master. Cluster thì sharding: chia key vào 16384 hash slot trên nhiều master, mỗi master có replica, failover tích hợp sẵn. Dữ liệu vừa một máy thì Sentinel; vượt một máy thì Cluster.
🇬🇧 English:
Sentinel is for a single master with replicas: it monitors the master, promotes a replica on failure and tells clients the new address. All data still lives on one master. Cluster shards data: keys are mapped to 16384 hash slots spread across several masters, each with replicas, and failover is built in. If the data fits on one machine I use Sentinel; if not, Cluster.
Q2. Redis Cluster chia key thế nào? Giống Kafka partition không?
🇻🇳 Tiếng Việt:
Slot bằng CRC16 của key mod 16384, mỗi master giữ một dải slot. Giống Kafka ở ý tưởng chia dữ liệu theo hash ra nhiều node, nhưng Kafka partition còn là đơn vị ordering và chia việc cho consumer group, Redis slot thì chỉ phân phối key. Lệnh nhiều key phải cùng slot, nên em dùng hash tag như
cart:{42}.
🇬🇧 English:
The slot is CRC16 of the key modulo 16384, and each master owns a range of slots. It is similar to Kafka in hashing data across nodes, but a Kafka partition is also the unit of ordering and of work distribution in a consumer group, while a Redis slot only distributes keys. Multi-key commands must hit the same slot, so I use hash tags like
cart:{42}.
Q3. Replication của Redis có mất dữ liệu không?
🇻🇳 Tiếng Việt:
Có thể, vì replication async. Write vừa được master xác nhận có thể mất khi failover. Cache thì chấp nhận được, nhưng với lock thì hai client có thể cùng giữ lock, nên em không để Redis lock là lớp bảo vệ duy nhất cho dữ liệu quan trọng.
🇬🇧 English:
Yes, because replication is asynchronous. A write acknowledged by the master can be lost during failover. That is fine for a cache, but for a lock two clients may end up holding it, so I never rely on a Redis lock as the only protection for critical data.
Cách nhớ ngắn gọn
- Replication = copy (async); Sentinel = tự failover; Cluster = sharding + failover.
- 16384 slot, CRC16(key); hash tag
{...}để gom key. - Kafka partition ≈ Redis slot ở việc chia dữ liệu, khác ở consumer/ordering.
- Failover có thể mất write cuối: cache ổn, lock thì nguy hiểm.
Tự kiểm tra
Redis Cluster có bao nhiêu hash slot, tính thế nào?
16384; slot = CRC16(key) mod 16384.
Hash tag dùng để làm gì?
Chỉ phần trong {} được hash, nên các key liên quan nằm cùng slot để dùng MGET, MULTI, Lua.
Lỗi MOVED nghĩa là gì?
Key thuộc slot ở node khác; client cluster-aware cập nhật topology và gửi lại tới node đúng.
Sentinel cần tối thiểu bao nhiêu node, vì sao?
Ba, để có quorum và tránh một sentinel bị cô lập quyết định sai.
Failover ảnh hưởng thế nào tới distributed lock?
Lock chưa replicate có thể mất, client khác lấy được lock, hai bên cùng chạy.