Design a Key-Value Store: System Architecture Diagram
CHAPTER 6: DESIGN A KEY-VALUE STORE
Mục tiêu bài viết
- Có cái nhìn tổng thể về kiến trúc của distributed key-value store sau khi đã học từng component riêng lẻ.
- Hiểu vai trò của coordinator node như một proxy giữa client và cluster.
- Nắm rõ tại sao thiết kế hoàn toàn phi tập trung (decentralized) là ưu điểm lớn.
- Biết mỗi node trong cluster cần đảm nhận những responsibilities gì.
1) Context
Sau khi đã đi qua tất cả các kỹ thuật:
- Data partition (consistent hashing)
- Data replication (N replicas)
- Consistency (quorum, W/R/N)
- Inconsistency resolution (vector clock)
- Failure detection (gossip protocol)
- Temporary failure (sloppy quorum + hinted handoff)
- Permanent failure (anti-entropy + Merkle tree)
Bây giờ là lúc tổng hợp tất cả thành một kiến trúc hoàn chỉnh.
2) Kiến trúc tổng quan
System Architecture — Figure 6-17
System Architecture Diagram (Figure 6-17):
n0
(blue)
/ \
n7 n1
(blue)
\ /
[Client] ──read/write──► n6 (coordinator) ◄──────── n2
◄──response──── (blue)
/ \
n5 n3
n4
Legend:
Blue nodes (n0, n1, n2) = replica nodes cho request hiện tại
n6 = coordinator (node nhận request từ client)
Dashed arrows = coordinator → replica nodes (put/get)
Solid arrows = coordinator ← replica nodes (response/ACK)
Consistent hashing ring:
n0 → n1 → n2 → n3 → n4 → n5 → n6 → n7 → (back to n0)
6 đặc điểm chính của kiến trúc:
1) Client API đơn giản:
- get(key)
- put(key, value)
Client không cần biết data nằm ở node nào.
2) Coordinator = proxy:
- Node nhận request đầu tiên từ client
- Tính hash(key) → xác định replica nodes
- Fan out request tới N replicas
- Collect responses và trả về cho client
3) Consistent hashing ring:
- Tất cả nodes phân bố trên ring
- Key → clockwise → server đầu tiên
- Add/remove node chỉ ảnh hưởng phần nhỏ key
4) Hoàn toàn decentralized:
- Không có master node
- Bất kỳ node nào cũng có thể là coordinator
- Add/remove node tự động, không cần manual config
5) Data replicated tại multiple nodes:
- N=3 mặc định
- Đặt ở distinct servers (và distinct DCs nếu có thể)
6) Không có SPOF:
- Mỗi node có CÙNG tập responsibilities
- Node nào down → các node khác vẫn phục vụ được
Node Responsibilities — Figure 6-18
Mỗi node trong cluster đảm nhận đầy đủ các trách nhiệm (không có node chuyên biệt):
┌──────────────────────────────────────────┐
│ NODE │
│ │
│ ┌─────────────┐ ┌──────────────────┐ │
│ │ Client API │ │ Failure detection│ │
│ └─────────────┘ └──────────────────┘ │
│ │
│ ┌─────────────┐ ┌──────────────────┐ │
│ │ Conflict │ │ Failure repair │ │
│ │ resolution │ │ mechanism │ │
│ └─────────────┘ └──────────────────┘ │
│ │
│ ┌─────────────┐ ┌──────────────────┐ │
│ │ Replication │ │ Storage engine │ │
│ └─────────────┘ └──────────────────┘ │
│ │
│ ┌─────────────┐ ┌──────────────────┐ │
│ │ ... │ │ ... │ │
│ └─────────────┘ └──────────────────┘ │
└──────────────────────────────────────────┘
Mỗi node đảm nhận:
- Client API → handle get/put từ client
- Failure detection → gossip protocol, membership list
- Conflict resolution → vector clock, reconciliation
- Failure repair → hinted handoff, anti-entropy (Merkle tree)
- Replication → sync data sang N replicas
- Storage engine → lưu trữ data (LSM-tree, B-tree, v.v.)
3) Request/Data flow
Full Write Flow (put)
PUT key="user:42", value={...} từ client:
1) Client → bất kỳ node nào trên ring (e.g., n6)
2) n6 trở thành coordinator cho request này
3) n6: hash("user:42") → vị trí trên ring
4) n6: đi clockwise → chọn N=3 unique servers: n0, n1, n2
5) n6 → n0: put("user:42", {...})
n6 → n1: put("user:42", {...})
n6 → n2: put("user:42", {...})
6) n0 ACK, n1 ACK (W=2 đạt → success)
7) n6 → Client: 200 OK
8) n2 ACK (async, không block client)
Full Read Flow (get)
GET key="user:42":
1) Client → n6 (coordinator)
2) n6: hash("user:42") → n0, n1, n2
3) n6 → n0: get("user:42")
n6 → n1: get("user:42")
4) n0 response: value_v1 (vector clock A)
n1 response: value_v1 (vector clock A) (R=2 đạt)
5) n6 so sánh responses:
- Nếu đồng nhất → trả về value ngay
- Nếu conflict → trả về cả hai versions cho client reconcile
6) n6 → Client: response
4) API / Data contract
Ví dụ API lấy thông tin topology của cluster:
GET /api/v1/cluster/topology
{
"clusterName": "kv-store-prod",
"ringAlgorithm": "consistent-hashing",
"hashFunction": "SHA-1",
"replicationFactor": 3,
"totalNodes": 8,
"nodes": [
{
"id": "n0",
"ip": "10.0.0.1",
"status": "online",
"virtualNodes": 200,
"ringPosition": "12.5%"
},
{
"id": "n1",
"ip": "10.0.0.2",
"status": "online",
"virtualNodes": 200,
"ringPosition": "25.0%"
},
{
"id": "n2",
"ip": "10.0.0.3",
"status": "online",
"virtualNodes": 200,
"ringPosition": "37.5%"
},
{
"id": "n3",
"ip": "10.0.0.4",
"status": "online",
"virtualNodes": 200,
"ringPosition": "50.0%"
},
{
"id": "n4",
"ip": "10.0.0.5",
"status": "online",
"virtualNodes": 200,
"ringPosition": "62.5%"
},
{
"id": "n5",
"ip": "10.0.0.6",
"status": "online",
"virtualNodes": 200,
"ringPosition": "75.0%"
},
{
"id": "n6",
"ip": "10.0.0.7",
"status": "online",
"virtualNodes": 200,
"ringPosition": "87.5%"
},
{
"id": "n7",
"ip": "10.0.0.8",
"status": "online",
"virtualNodes": 200,
"ringPosition": "100.0%"
}
],
"decentralized": true,
"singlePointOfFailure": false
}
5) Trade-offs
| Thiết kế | Centralized (có master) | Decentralized (peer-to-peer) |
|---|---|---|
| SPOF | Có — master là SPOF | Không — mọi node đều bình đẳng |
| Routing | Đơn giản — client hỏi master | Phức tạp hơn — coordinator tự tính |
| Scalability | Bị giới hạn bởi master | Scale tuyến tính với số node |
| Consistency | Dễ đảm bảo (master là source of truth) | Cần quorum, vector clock |
| Fault tolerance | Thấp nếu master down | Cao — node nào cũng thay thế được |
| Ví dụ | Redis Cluster (với primary/replica) | Amazon Dynamo, Cassandra |
6) Tóm tắt + bài học
- Coordinator = proxy: nhận request từ client, routing tới đúng replica nodes, collect response — nhưng bất kỳ node nào cũng có thể là coordinator.
- Decentralized hoàn toàn: không có master, không có SPOF. Mọi node đều có cùng responsibilities.
- Mỗi node phải tự xử lý: Client API, Failure detection (gossip), Conflict resolution (vector clock), Failure repair (hinted handoff + Merkle tree), Replication, Storage.
- Consistent hashing ring là backbone của toàn bộ hệ thống: quyết định data ở đâu, ai chịu trách nhiệm, và khi topology thay đổi thì impact nhỏ.
Bài tiếp theo sẽ đi vào chi tiết Write Path và Read Path — luồng data chạy qua các layer bên trong một node khi có write/read request.