分布式部署 #
本章介绍 Qdrant 的分布式架构和高可用部署方案。
分布式架构概述 #
text
Qdrant 分布式架构:
┌─────────────────────────────────────────────────────────────┐
│ Client Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ REST API │ │ gRPC │ │ SDK │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Consensus Layer │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Raft Consensus │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Leader │ │Follower │ │Follower │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Data Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Shard 1 │ │ Shard 2 │ │ Shard 3 │ │
│ │ ┌───┬───┐ │ │ ┌───┬───┐ │ │ ┌───┬───┐ │ │
│ │ │ R │ R │ │ │ │ R │ R │ │ │ │ R │ R │ │ │
│ │ │ 1 │ 2 │ │ │ │ 1 │ 2 │ │ │ │ 1 │ 2 │ │ │
│ │ └───┴───┘ │ │ └───┴───┘ │ │ └───┴───┘ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
核心概念 #
分片(Sharding) #
text
分片策略:
Collection 数据分布:
┌─────────────────────────────────────────────────────────────┐
│ Collection │
│ 总数据:100 万向量 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Shard 1 Shard 2 Shard 3 │
│ 33 万向量 33 万向量 34 万向量 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Node A │ │ Node B │ │ Node C │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
分片优势:
├── 水平扩展
├── 并行查询
└── 负载均衡
复制(Replication) #
text
复制策略:
每个分片有多个副本:
┌─────────────────────────────────────────────────────────────┐
│ Shard 1 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Replica 1 Replica 2 Replica 3 │
│ (Leader) (Follower) (Follower) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Node A │ │ Node B │ │ Node C │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ 写操作 → Leader │
│ 读操作 → 任意副本 │
│ │
└─────────────────────────────────────────────────────────────┘
复制优势:
├── 数据冗余
├── 高可用
└── 读写分离
一致性级别 #
text
一致性级别:
强一致性(Strong):
├── 等待所有副本确认
├── 最高数据可靠性
└── 最低性能
多数一致性(Majority):
├── 等待多数副本确认
├── 平衡可靠性和性能
└── 推荐默认选择
弱一致性(Weak):
├── 不等待副本确认
├── 最高性能
└── 可能数据丢失
集群部署 #
Docker Compose 部署 #
yaml
version: '3.8'
services:
qdrant-node-1:
image: qdrant/qdrant:latest
ports:
- "6333:6333"
- "6334:6334"
volumes:
- ./node1/storage:/qdrant/storage
environment:
- QDRANT__CLUSTER__ENABLED=true
- QDRANT__CLUSTER__P2P__PORT=6335
command: ./qdrant --uri "http://qdrant-node-1:6335"
qdrant-node-2:
image: qdrant/qdrant:latest
ports:
- "6336:6333"
- "6337:6334"
volumes:
- ./node2/storage:/qdrant/storage
environment:
- QDRANT__CLUSTER__ENABLED=true
- QDRANT__CLUSTER__P2P__PORT=6335
command: ./qdrant --uri "http://qdrant-node-2:6335"
qdrant-node-3:
image: qdrant/qdrant:latest
ports:
- "6338:6333"
- "6339:6334"
volumes:
- ./node3/storage:/qdrant/storage
environment:
- QDRANT__CLUSTER__ENABLED=true
- QDRANT__CLUSTER__P2P__PORT=6335
command: ./qdrant --uri "http://qdrant-node-3:6335"
Kubernetes 部署 #
yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: qdrant-cluster
spec:
serviceName: qdrant-headless
replicas: 3
selector:
matchLabels:
app: qdrant
template:
metadata:
labels:
app: qdrant
spec:
containers:
- name: qdrant
image: qdrant/qdrant:latest
ports:
- containerPort: 6333
name: http
- containerPort: 6334
name: grpc
- containerPort: 6335
name: p2p
env:
- name: QDRANT__CLUSTER__ENABLED
value: "true"
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
command:
- ./qdrant
- --uri
- "http://$(POD_IP):6335"
volumeMounts:
- name: data
mountPath: /qdrant/storage
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 50Gi
---
apiVersion: v1
kind: Service
metadata:
name: qdrant-headless
spec:
clusterIP: None
selector:
app: qdrant
ports:
- port: 6333
name: http
- port: 6334
name: grpc
- port: 6335
name: p2p
---
apiVersion: v1
kind: Service
metadata:
name: qdrant
spec:
selector:
app: qdrant
ports:
- port: 6333
name: http
targetPort: 6333
- port: 6334
name: grpc
targetPort: 6334
type: ClusterIP
Helm 部署 #
bash
helm repo add qdrant https://qdrant.github.io/qdrant-helm
helm repo update
helm install qdrant qdrant/qdrant \
--set replicaCount=3 \
--set cluster.enabled=true \
--set persistence.size=100Gi \
--set resources.requests.memory=8Gi \
--set resources.requests.cpu=2
集群管理 #
创建集群 Collection #
python
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams
client = QdrantClient(url="http://localhost:6333")
client.create_collection(
collection_name="distributed_collection",
vectors_config=VectorParams(size=384, distance=Distance.COSINE),
shard_number=3,
replication_factor=2,
write_consistency_factor=1
)
print("分布式 Collection 创建成功")
集群参数说明 #
| 参数 | 说明 | 推荐值 |
|---|---|---|
| shard_number | 分片数量 | 节点数或其倍数 |
| replication_factor | 副本数量 | 2-3 |
| write_consistency_factor | 写确认副本数 | 1-2 |
| read_consistency_factor | 读确认副本数 | 1 |
查看集群状态 #
python
cluster_info = client.get_cluster_info()
print(f"集群状态: {cluster_info.status}")
print(f"节点数量: {cluster_info.number_of_peers}")
print(f"Raft 状态: {cluster_info.raft_info}")
for peer in cluster_info.peers:
print(f"节点: {peer.uri}")
print(f" 状态: {peer.state}")
查看分片分布 #
python
collection_info = client.get_collection("distributed_collection")
for shard in collection_info.shards:
print(f"分片 {shard.shard_id}:")
print(f" 状态: {shard.state}")
print(f" 节点: {shard.peer_id}")
数据迁移 #
集群引导 #
python
from qdrant_client.models import PeerInfo
client.add_peer(
uri="http://new-node:6335"
)
print("新节点已加入集群")
移除节点 #
python
client.remove_peer(
peer_id=2
)
print("节点已从集群移除")
数据重平衡 #
python
client.update_collection(
collection_name="distributed_collection",
optimizer_config=OptimizersConfigDiff(
deleted_threshold=0.2
)
)
高可用配置 #
多可用区部署 #
yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: qdrant-cluster
spec:
serviceName: qdrant-headless
replicas: 6
template:
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: qdrant
topologyKey: topology.kubernetes.io/zone
containers:
- name: qdrant
image: qdrant/qdrant:latest
健康检查配置 #
yaml
livenessProbe:
httpGet:
path: /health
port: 6333
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 6333
initialDelaySeconds: 5
periodSeconds: 5
负载均衡配置 #
yaml
apiVersion: v1
kind: Service
metadata:
name: qdrant-lb
spec:
selector:
app: qdrant
ports:
- port: 6333
targetPort: 6333
type: LoadBalancer
一致性配置 #
写一致性 #
python
from qdrant_client.models import WriteOrdering
client.upsert(
collection_name="distributed_collection",
points=[point],
wait=True,
ordering=WriteOrdering.STRONG
)
读一致性 #
python
from qdrant_client.models import ReadConsistency
results = client.search(
collection_name="distributed_collection",
query_vector=[0.1] * 384,
consistency=ReadConsistency.MAJORITY
)
监控和运维 #
集群健康检查 #
python
def check_cluster_health():
try:
info = client.get_cluster_info()
if info.status != "enabled":
return {"status": "unhealthy", "reason": "Cluster not enabled"}
for peer in info.peers:
if peer.state != "Active":
return {"status": "degraded", "reason": f"Peer {peer.peer_id} not active"}
return {"status": "healthy"}
except Exception as e:
return {"status": "error", "reason": str(e)}
health = check_cluster_health()
print(f"集群健康状态: {health}")
分片状态监控 #
python
def monitor_shards(collection_name):
info = client.get_collection(collection_name)
shards_status = {
"green": 0,
"yellow": 0,
"red": 0
}
for shard in info.shards:
if shard.state == "Active":
shards_status["green"] += 1
elif shard.state == "Partial":
shards_status["yellow"] += 1
else:
shards_status["red"] += 1
return shards_status
status = monitor_shards("distributed_collection")
print(f"分片状态: {status}")
故障恢复 #
节点故障处理 #
text
节点故障恢复流程:
1. 检测故障
└── 心跳超时
2. 重新选举
└── Raft 选举新 Leader
3. 数据同步
└── 从其他副本同步数据
4. 恢复服务
└── 节点重新加入集群
数据恢复 #
python
def recover_collection(collection_name):
info = client.get_collection(collection_name)
if info.status == "red":
print(f"Collection {collection_name} 需要恢复")
client.update_collection(
collection_name=collection_name,
optimizer_config=OptimizersConfigDiff(
deleted_threshold=0.1
)
)
recover_collection("distributed_collection")
最佳实践 #
集群规模建议 #
text
集群规模建议:
小规模(< 100 万向量):
├── 节点数:3
├── 分片数:3
├── 副本数:2
└── 单节点配置:4C8G
中等规模(100-1000 万向量):
├── 节点数:5
├── 分片数:5
├── 副本数:2
└── 单节点配置:8C16G
大规模(> 1000 万向量):
├── 节点数:7+
├── 分片数:节点数 × 2
├── 副本数:3
└── 单节点配置:16C32G+
网络配置 #
yaml
network:
bind: 0.0.0.0
cluster:
enabled: true
p2p:
port: 6335
connection_pool_size: 20
consensus:
tick_period_ms: 100
heartbeat_timeout_ms: 500
小结 #
本章详细介绍了分布式部署:
- 分布式架构原理
- 分片和复制策略
- 集群部署方法
- 高可用配置
- 监控和故障恢复
下一步 #
掌握分布式部署后,继续学习 快照与备份,了解数据备份和恢复策略!
最后更新:2026-04-04