7.15 Phân tán: shard, replica, Raft
Mục này bắt đầu bằng câu quan trọng nhất, vì hiểu sai nó dẫn tới kỳ vọng sai về toàn bộ hệ:
Raft trong Qdrant quản hình dạng của cụm, không quản dữ liệu của bạn.
Collection nào tồn tại, peer nào giữ shard nào, replication factor bao nhiêu — những thứ đó đi qua đồng thuận Raft. Thao tác trên point thì không.
Đây là một quyết định thiết kế có chủ ý, và nó đánh đổi consistency lấy throughput. Nếu mọi
lần upsert đều phải qua Raft, throughput ghi sẽ sập. Cái giá là mô hình consistency yếu
hơn, và đó là chủ đề của 7.16.
Ba tầng: collection → shard → segment
Phần tiêu đề “Ba tầng: collection → shard → segment”Collection "tai_lieu" ├── Shard 0 ──► ReplicaSet ──┬── replica trên peer A ← các replica │ └── replica trên peer B ├── Shard 1 ──► ReplicaSet ──┬── replica trên peer B │ └── replica trên peer C └── Shard 2 ──► ...
Mỗi replica = một tập segment đầy đủ (xem 7.4)Shard là đơn vị phân chia dữ liệu. Replica là đơn vị dự phòng. Một truy vấn phải chạm mọi shard (mỗi shard một replica) rồi gộp kết quả — giống hệt cách một truy vấn phải chạm mọi segment trong một shard.
shard_number — con số bạn không sửa được
Phần tiêu đề “shard_number — con số bạn không sửa được”Đây là quyết định đắt nhất khi tạo collection ở bản tự host.
- Mặc định: số node trong cụm tại thời điểm tạo collection.
- Không đổi được sau đó (Qdrant Cloud có resharding từ v1.13; bản tự host thì chưa).
Khuyến nghị của Qdrant: ít nhất 2 shard mỗi node, và chọn một con số có nhiều ước để sau này chia lại được. Ví dụ họ đưa ra: 12 shard cho phép chạy trên 1 → 2 → 3 → 6 → 12 node mà vẫn chia đều.
Chọn
shard_numberquá nhỏ ⇒ không mở rộng ngang được mà không nạp lại. Chọn quá lớn ⇒ mỗi truy vấn phải fan-out tới quá nhiều nơi, latency đuôi xấu đi. Đây là chỗ đáng dừng lại suy nghĩ 15 phút trước khi gõ lệnh tạo collection.
sharding_method: auto và custom
Phần tiêu đề “sharding_method: auto và custom”auto (mặc định) | custom | |
|---|---|---|
| Điểm rơi vào shard nào | consistent hashing theo ID | theo shard_key bạn chỉ định |
| Bạn kiểm soát vị trí | không | có |
| Dùng khi | mặc định | multitenancy, partition theo thời gian |
Với custom, số shard vật lý = shard_number × số shard_key × replication_factor. Và có
một chi tiết dễ bỏ sót: ID chỉ phải duy nhất trong phạm vi một shard key — hai shard
key khác nhau có thể chứa cùng một point ID.
Công dụng thật của custom:
- Gom một khách hàng lớn vào shard riêng. Xem 7.17.
- Partition theo thời gian. Mỗi tháng một shard key. Xoá dữ liệu cũ = xoá nguyên một shard, thay vì xoá hàng triệu điểm rồi chờ vacuum (7.6). Đây là mẹo vận hành rất đáng giá cho dữ liệu có vòng đời.
- Tuân thủ dữ liệu theo vùng. Dữ liệu khách hàng EU nằm trên peer đặt ở EU.
replication_factor
Phần tiêu đề “replication_factor”Mặc định 1 — nghĩa là không có replica nào. Một node chết là mất shard đó.
Ở bản tự host, replica không tự sinh ra: bạn tạo và gỡ chúng bằng tay, và việc đổi
replication_factor trong cấu hình không tự nhân bản dữ liệu đang có. Qdrant Cloud thì
tự động duy trì đúng số replica.
Chi phí là tuyến tính: replication_factor: 2 nghĩa là gấp đôi dung lượng lưu trữ.
Chuyển shard: ba phương pháp
Phần tiêu đề “Chuyển shard: ba phương pháp”Khi thêm node, cân bằng lại, hoặc phục hồi sau sự cố, Qdrant phải di chuyển shard. Ba cách, và chọn sai thì hoặc chậm hoặc sai:
| Phương pháp | Có từ | Chuyển cả index? | Thứ tự ghi | Đánh đổi |
|---|---|---|---|---|
stream_records | v0.8 | ❌ dựng lại ở đích | weak | Chậm (phải xây lại HNSW), nhưng không cần thêm đĩa |
snapshot | v1.7 | ✅ (cả quantization) | strong | Nhanh, nhưng cần thêm dung lượng đĩa |
wal_delta | v1.8 | ❌ | strong | Chỉ dùng được khi đích đã có shard đó — dành cho phục hồi |
wal_delta là thứ Qdrant tự dùng khi một node quay lại sau khi rớt mạng ngắn: chỉ phát lại
phần WAL còn thiếu thay vì chép lại toàn bộ shard. Rất rẻ, nhưng chỉ áp dụng được cho tình
huống đó.
Mặc định là null — Qdrant tự chọn.
Khi một node chết
Phần tiêu đề “Khi một node chết”Điều gì xảy ra phụ thuộc hoàn toàn vào replication_factor:
replication_factor: 1 | replication_factor: 2 | |
|---|---|---|
| Shard trên node đó | Không truy cập được | Còn replica, vẫn phục vụ |
| Truy vấn | Lỗi hoặc thiếu kết quả | Bình thường |
| Ghi | Lỗi cho shard đó | Bình thường, tuỳ write_consistency_factor |
| Phục hồi | Từ snapshot (7.19) | Tự động, thường bằng wal_delta |
Raft phát hiện node mất kết nối bằng ping định kỳ, chu kỳ đặt bởi tick_period_ms
(mặc định 100). Giảm nó thì phát hiện nhanh hơn nhưng tốn overhead hơn.
⚠️
replication_factor: 1không phải là “chưa cần lo về HA”. Nó là “một node chết thì một phần corpus biến mất khỏi kết quả tìm kiếm, và không có lỗi rõ ràng nào cho ứng dụng biết là kết quả đang thiếu.” Đây là chế độ hỏng âm thầm, giống họ với các chế độ hỏng ở 7.8.
Cân bằng tải và node đặc biệt
Phần tiêu đề “Cân bằng tải và node đặc biệt”Cân bằng tải là việc của bạn ở bản tự host — Qdrant không tự làm. Mọi peer đều nhận được request và sẽ chuyển tiếp tới nơi cần, nhưng peer nhận request phải gánh phần điều phối, nên dồn hết vào một node là lãng phí.
Listener node (node_type: "Listener") là chế độ thử nghiệm: nhận mọi cập nhật (xử lý
như wait=false) nhưng không tham gia trả lời truy vấn. Dùng để dựng một node chuyên
làm backup, hoặc đồng bộ sang vùng khác mà không ảnh hưởng đường phục vụ.
Bốn câu hỏi trước khi lên cụm
Phần tiêu đề “Bốn câu hỏi trước khi lên cụm”shard_numberlà bao nhiêu, và nó chia được cho những số node nào? Sai là nạp lại.replication_factorđã > 1 chưa? Nếu chưa, bạn đang chấp nhận mất dữ liệu âm thầm.- Tôi có cần
customsharding không? Multitenancy và dữ liệu theo thời gian là hai dấu hiệu rõ ràng nhất. - Fusion của tôi có nằm trong prefetch không? Nếu có, nó đang tính theo từng shard — xem 7.12. Đây là bug chỉ xuất hiện khi lên nhiều shard.