Qdrant 集群模式部署指南
Qdrant v1.15.3 三节点分布式集群部署指南:Raft 共识与分片副本原理、--uri/--bootstrap 顺序启动拉齐、建复制集合同写一致性验证、节点故障转移与自动回补,覆盖配置文件与系统d 全部流程
Qdrant 集群模式部署指南
目标:在三台真实 Ubuntu 22.04 服务器(qdrant-node1/2/3)上部署 Qdrant v1.15.3 分布式集群,通过 Raft 共识 + gossip 自动组网,配置
cluster.enabled、cluster.p2p.port、首节点--uri声明自身地址与后续节点--bootstrap加入,并按严格顺序启动。文档覆盖集群原理、三节点配置、顺序启动、集群状态验证、复制集合同写一致性、故障转移与--reinit恢复,全程基于真实服务器视角。
重要前置说明:本文档为伪集群环境
本文档描述的是 Qdrant 集群模式(distributed mode),通过 Raft 共识协议 + gossip 自动组网,把多台服务器联合成一个逻辑集群。部署视角必须假设为三台真实的 Ubuntu 22.04 服务器,主机名分别为 qdrant-node1 / qdrant-node2 / qdrant-node3。每台机器的安装方式与单节点完全一致(二进制 /opt/qdrant/qdrant、数据 /storage/qdrant、配置 /etc/qdrant/config.yaml、systemd 托管),差异只体现在配置中的集群项与启动参数上。
技术提醒:本文的「伪集群」指在小型环境里用虚拟机/受限资源模拟三节点集群用于验证,并不改变任何集群配置与部署模型——三台服务器就是三台真正独立的向量服务进程,通过 6335 P2P 端口相互通信,语义与生产集群等价。
一、集群架构与原理
Qdrant 在集群模式下自动启用两个核心机制:
1.1 Raft 共识协议
Qdrant 使用 Raft 协议维护集群的共识状态(元数据,如节点列表、集合定义、分片分布)。集群内会选举出一个 Leader(raft_info.leader) 负责协调共识,其余为 Follower / Voter。节点间通过 gossip 传播集群成员与分片信息。
- Raft 保证集群中所有节点对「集群该是什么样」达成一致,即使出现分区或节点故障。
- 时钟同步对 Raft 选举至关重要,三台服务器必须开启 NTP。
1.2 分片与副本
- 分片(Shard):一个集合的数据被切分成
shard_number个分片,分布在集群不同节点上。 - 副本(Replica):每个分片在多个节点上保存副本,副本数由
replication_factor控制。副本越多,单点故障后数据越不易丢失、读可用性越高。 - 节点角色(node_type):普通节点承担读、写、索引与复制;部分拓扑还可能配置专用 follower。
Readiness 与 QoS:集群就绪要求每个集合的分片在指定副本数下达到可读状态,
/readyz会等到all shards are ready才返回 200。
1.3 写一致性(write consistency)
write_consistency_factor 定义一次写操作在返回成功前,必须有多少个副本确认写入。它需满足:write_consistency_factor ≤ 存活副本数。
- 例如
replication_factor=3、write_consistency_factor=2:写请求只要被 ≥2 个副本确认即返回acknowledged,容错能力更强。 - 若存活副本数不足该值,写操作会被拒绝(返回
Collection is not available或类似错误)。
1.4 集群配置三要素
启用分布式集群只需在每台服务器的 config.yaml 中配置三件事:
cluster.enabled: true—— 开启集群模式;cluster.p2p.port: 6335—— 节点间 gossip/Raft 通信端口;- 启动参数:首节点用
--uri声明自身地址,后续节点用--bootstrap加入首节点(详见第五节)。
cluster:
enabled: true
p2p:
port: 6335
二、环境与 IP 规划
| 主机名 | 内网 IP | 角色 |
|---|---|---|
qdrant-node1 | 192.168.100.11 | 首个引导节点(bootstrapper),用自己的 --uri 声明地址 |
qdrant-node2 | 192.168.100.12 | 通过 --bootstrap 加入 node1 |
qdrant-node3 | 192.168.100.13 | 通过 --bootstrap 加入 node1 |
端口规划:
| 端口 | 用途 |
|---|---|
| 6333 | HTTP REST API |
| 6334 | gRPC |
| 6335 | P2P(nodes 间 gossip 与 Raft,集群部署必须开放) |
统一要求(三台一致):
- 操作系统 Ubuntu 22.04.5 LTS,x86_64,内核 6.8.x。
- Qdrant 版本 v1.15.3(三台必须同版本,避免协议差异)。
- 安装目录
/opt/qdrant、数据/storage/qdrant、配置/etc/qdrant/config.yaml。 - 主机名必须设为
qdrant-node1/2/3,并在/etc/hosts中配置三台主机名互相解析(推荐用 hostname/DNS 而不是 IP 相互访问,详见 7.3 的实测经验)。 - 三台时间经 NTP 对齐(Raft 选举对时钟敏感)。
# 每台分别设置主机名,例如 node1:
sudo hostnamectl set-hostname qdrant-node1
# /etc/hosts 追加(三台都写)
192.168.100.11 qdrant-node1
192.168.100.12 qdrant-node2
192.168.100.13 qdrant-node3
三、各节点安装(与单节点一致)
三台服务器的二进制安装完全复用单节点流程。以下命令在 每一台 服务器上执行。
3.1 安装依赖与下载二进制
sudo apt-get update && sudo apt-get install -y curl gzip tar libunwind-dev
export QDRANT_VERSION=v1.15.3
mkdir -p ${QDRANT_VERSION} && cd ${QDRANT_VERSION}
curl -L -O "https://github.com/qdrant/qdrant/releases/download/${QDRANT_VERSION}/qdrant-x86_64-unknown-linux-gnu.tar.gz"
tar -xzf qdrant-x86_64-unknown-linux-gnu.tar.gz
3.2 布置安装目录
sudo mkdir -p /opt/qdrant /etc/qdrant /storage/qdrant
sudo cp qdrant /opt/qdrant/qdrant
sudo chmod +x /opt/qdrant/qdrant
sudo cp config/config.yaml /etc/qdrant/config.yaml
ldd /opt/qdrant/qdrant | grep -i "not found" # 无输出则依赖齐全
/opt/qdrant/qdrant --version # 预期:qdrant 1.15.3
四、集群配置
4.1 编写 /etc/qdrant/config.yaml(三台相同)
在单节点配置基础上,把 cluster.enabled 置为 true 并开启 p2p 端口,同时显式给出 replication_factor 与 write_consistency_factor:
log_level: INFO
storage:
storage_path: /storage/qdrant
snapshots_path: /storage/qdrant/snapshots
on_disk_payload: true
wal:
wal_capacity_mb: 32
node_type: "Normal"
performance:
max_search_threads: 0
optimizer_cpu_budget: 0
collection:
replication_factor: 3 # 三节点集群,副本数设为 3
write_consistency_factor: 2 # 写一致性:需 ≥2 副本确认
service:
host: 0.0.0.0
http_port: 6333
grpc_port: 6334
enable_cors: true
cluster:
enabled: true # 关键要素 1:开启分布式集群
p2p:
port: 6335 # 关键要素 2:节点间通信端口
consensus:
tick_period_ms: 100 # Raft tick 周期
compact_wal_entries: 128 # WAL 压缩点
telemetry_disabled: false
说明:
cluster.consensus.tick_period_ms: 100控制 Raft 的 tick 间隔,越小选举与心跳越密集,但对 CPU 有一定消耗,一般保持默认。cluster.consensus.compact_wal_entries: 128控制共识 WAL 每累积多少条日志触发压缩,避免 WAL 无限增长。replication_factor与write_consistency_factor在配置文件里给出默认值;建集合时也可在请求体中显式指定(见第七节)。
4.2 创建 systemd 服务
三台各写一份 systemd 单元,启动参数不同(见 4.3):
node1(首节点,用 --uri 声明自身地址):
# /etc/systemd/system/qdrant.service
[Unit]
Description=Qdrant Vector Search Engine (node1)
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/qdrant
ExecStart=/opt/qdrant/qdrant --config-path /etc/qdrant/config.yaml --uri http://192.168.100.11:6335
Restart=on-failure
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
node2 / node3(后续节点,用 --bootstrap 加入 node1):
# /etc/systemd/system/qdrant.service
[Unit]
Description=Qdrant Vector Search Engine
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/qdrant
ExecStart=/opt/qdrant/qdrant --config-path /etc/qdrant/config.yaml --bootstrap http://192.168.100.11:6335
Restart=on-failure
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
4.3 关键启动参数解析
| 参数 | 用途 | 用在 |
|---|---|---|
--uri http://<node1-ip>:6335 | 首节点必须用它声明自身地址,让首节点知道自己对外可寻址的地址,从而能接受其他节点加入 | 仅 node1 |
--bootstrap http://<node1-ip>:6335 | 告诉后续节点「需要加入的既有集群地址」,通过它向集群发出加入请求 | node2、node3 |
--uri与--bootstrap是集群接入的两种互补方式:首节点没有可加入的对象,只能以--uri声明自己成为集群的种子/引导节点;其余节点都有同一个可投靠的地址,故用--bootstrap。两者都必须指向节点的 P2P 端口 6335,而不是 HTTP 6333。
五、顺序启动(严格时序)
集群组网对启动顺序敏感,必须严格按序启动,上一节点确认成为集群一员后再启动下一节点。
5.1 启动首节点 node1
sudo systemctl daemon-reload
sudo systemctl enable --now qdrant
sudo systemctl status qdrant --no-pager
node1 以 --uri 启动后会自行初始化共识并选举自己为 Leader(consensus 大约 4 秒)。可通过集群接口确认:
curl http://127.0.0.1:6333/cluster
预期:集群已启用,peers 目前只有 node1 一个,且 raft_info.leader 指向本节点。
{
"result": {
"status": "enabled",
"peers": { "存在本节点 peer_id 的键": { "uri": "http://192.168.100.11:6335/", "name": "..." } },
"raft_info": { "leader": "本节点 uuid", "role": "Leader", "term": 1 }
}
}
等待 node1 成为 Leader 后再继续,否则后续节点加入时首节点可能尚未就绪。
5.2 依次启动 node2、node3
等 node1 成为 Leader 后,再启动 node2,等待它作为 peer 加入集群,然后再启动 node3:
# 在 node2 上:
sudo systemctl enable --now qdrant
# 在 node3 上:
sudo systemctl enable --now qdrant
每一步之间都可在 node1 上查看成员变化:
curl http://192.168.100.11:6333/cluster | python3 -m json.tool
预期:peers 逐步从 1 → 2 → 3,最终包含全部三个节点。
六、集群状态验证
在任意节点(通常选 node1)发起集群体检:
curl http://127.0.0.1:6333/cluster | python3 -m json.tool
关键字段及预期:
| 字段 | 预期 |
|---|---|
result.status | enabled |
result.peers | 含 3 个节点(node1/2/3) |
result.raft_info.leader | 某个节点 uuid,即当前 Leader |
result.raft_info.role | Leader(Leader 自身)或 Follower(其余节点) |
各 peer 的 uri | 指向各节点的 :6335 P2P 地址 |
同时在 node2、node3 上分别执行 curl http://127.0.0.1:6333/cluster,确认三台看到的是同一个 3 节点集群拓扑(Raft 一致性)。
端口监听确认(三台):
ss -tlnp | grep -E "6333|6334|6335"
# 预期:6333(HTTP)、6334(gRPC)、6335(P2P)均监听
七、创建复制集合并验证写一致性
7.1 创建带副本的集合 cdemo
任选一个节点(推荐 Leader / node1)创建集合,指定分片与副本:
curl -X PUT http://127.0.0.1:6333/collections/cdemo \
-H "Content-Type: application/json" \
-d '{
"vectors": {"size": 4, "distance": "Cosine"},
"shard_number": 2,
"replication_factor": 3,
"write_consistency_factor": 2
}'
参数说明:
shard_number: 2—— 数据分为 2 个分片;replication_factor: 3—— 每个分片在 3 台节点上各存一份副本(建议节点数 ≥ 副本数 rf,即 rf=3 时节点数最好 ≥3);write_consistency_factor: 2—— 写成功需 ≥2 个副本确认(必须 ≤ 存活副本率,否则无可写副本时写会被拒)。
7.2 向 node1 写入 3 个点
curl -X PUT http://127.0.0.1:6333/collections/cdemo/points \
-H "Content-Type: application/json" \
-d '{
"points": [
{"id": 1, "vector": [0.1, 0.2, 0.3, 0.4]},
{"id": 2, "vector": [0.5, 0.6, 0.7, 0.8]},
{"id": 3, "vector": [0.9, 0.1, 0.2, 0.3]}
]
}'
# 预期:{"result":{"operation_id":0,"status":"acknowledged"},"status":"ok"}
7.3 跨节点读取一致性验证
在三台节点上分别执行 count,确认数据已通过副本机制复制到每个节点:
# node1
curl -X POST http://127.0.0.1:6333/collections/cdemo/points/count -H "Content-Type: application/json" -d '{"exact": true}'
# node2
curl -X POST http://192.168.100.12:6333/collections/cdemo/points/count -H "Content-Type: application/json" -d '{"exact": true}'
# node3
curl -X POST http://192.168.100.13:6333/collections/cdemo/points/count -H "Content-Type: application/json" -d '{"exact": true}'
三台均预期返回 count: 3,说明单个写入被复制到全部副本,跨节点数据一致。
部署建议(实测经验):在跨节点调用的 URL 中,优先使用 hostname/DNS 而不是 IP。实测发现节点用 IP 自访问偶发瞬时
connection refused,改用主机名(已写入/etc/hosts)访问最稳定。因此表 7-1 的调用在对接业务/监控时建议写http://qdrant-node1:6333等主机名形式。
八、故障转移验证
模拟单点故障,验证集群高可用与自动恢复。
8.1 停止 node1
# 在 node1 上:
sudo systemctl stop qdrant
此时集群有 3 副本中的 2 个仍然存活(node2、node3),write_consistency_factor=2 仍可被满足。
8.2 剩余节点仍可读写
向 node2 写入 1 个新点:
curl -X PUT http://127.0.0.1:6333/collections/cdemo/points \ # 在 node2 上执行
-H "Content-Type: application/json" \
-d '{"points": [{"id": 4, "vector": [0.2, 0.1, 0.4, 0.3]}]}'
# 预期:acknowledged
在 node3 上做 count,确认新数据已同步到存活的副本:
curl -X POST http://127.0.0.1:6333/collections/cdemo/points/count -H "Content-Type: application/json" -d '{"exact": true}'
# 预期:count: 4
结论:即使 Leader 所在的 node1 宕机,集群仍能重新选举 Leader 并继续对外读写,不承担数据丢失(副本仍在 node2/3)。
8.3 重启 node1 自动重新加入
sudo systemctl start qdrant # 在 node1 上
重启后 node1 通过既有的集群状态自动重新加入,并在 node1 上 count:
curl -X POST http://127.0.0.1:6333/collections/cdemo/points/count -H "Content-Type: application/json" -d '{"exact": true}'
# 预期:count: 4
关键点:node1 离线期间写入的点(id=4)在它重新加入后已自动同步回来,
count从 3 变为 4。这正是 Raft 自动追赶(catch-up) 机制的作用——落伍节点基于共识日志追平其缺失的最新写入,无需手工干预。此时curl .../cluster应恢复到 3 个 peers。
九、扩缩容与 --reinit 恢复
9.1 扩容节点
新增第 4 台服务器(如 qdrant-node4),装好同一版本二进制,配置 cluster.enabled: true,再以 --bootstrap http://192.168.100.11:6335 启动即可自动加入现有集群。
9.2 缩容节点
在待下线节点上先停止服务:
sudo systemctl stop qdrant
移除后,余下节点的 peers 会自动感知掉线;若副本数仍能满足,服务不中断。若要永久下线,可按顺序停止并清理该系统服务。
9.3 --reinit:集群共识状态损坏时的恢复
--reinit 是在集群共识状态损坏时的恢复手段。当节点因 WAL/共识目录损坏等原因无法从自身状态继续时,可用它强制节点重新初始化共识链路:
/opt/qdrant/qdrant --config-path /etc/qdrant/config.yaml --reinit --bootstrap http://192.168.100.11:6335
--reinit会保留该节点的 peer_id,丢弃损坏的共识状态,从而从 bootstrap 地址重新接收当前集群状态。- 若该节点原本就是集群中唯一的 Leader/首节点(无 bootstrap 可投靠),则用它把自己的状态重建提升为首节点:
/opt/qdrant/qdrant --config-path /etc/qdrant/config.yaml --reinit --uri http://<自身IP>:6335。 - 执行前务必先停止对应 systemd 服务,或直接用
--reinit覆盖 systemd 的ExecStart临时启动;确认恢复后改回正常启动参数。
操作风险:
--reinit只重建共识状态、不删业务分片数据,但使用前仍建议先备份/storage/qdrant,并只针对确实损坏的节点执行。
十、常见问题
-
集群状态不是
enabled,或peers只有自己 检查cluster.enabled: true与cluster.p2p.port: 6335是否配置;确认 6335 端口在防火墙放行;确认--uri/--bootstrap指向的是 P2P 端口 6335。 -
后续节点一直加入不进来 首节点必须已用
--uri启动并成为 Leader(等待约 4 秒 consensus)后才可被 bootstrap;按「node1 → node2 → node3」顺序,不要并发同时启动。 -
写请求被拒,提示集合不可用 / consistency 不满足
write_consistency_factor不能高于当前存活副本数。副本 2/3 存活时仍可写(因子 ≤2);副本不足该值时需等待副本恢复或调低因子。 -
count 在各节点不一致 确认写请求返回的是
acknowledged而非enqueued/拒绝;等待副本同步;用exact: true的 count 并配合集群拓扑校验。 -
节点自访问瞬时 refused 节点间调用改用 hostname/DNS(写进
/etc/hosts)而非 IP 直连,最稳定(实测经验)。 -
共识 WAL 不断增长 检查
cluster.consensus.compact_wal_entries(如 128)是否生效,必要时调小触发值。 -
节点重启后 peer 仍显示离线 等待节点 catch-up 完成即可;若长时间未恢复且共识状态损坏,按第九节用
--reinit恢复。 -
卸载某台节点 先
sudo systemctl disable --now qdrant,再清理/opt/qdrant、/etc/qdrant、/storage/qdrant(谨慎,会删数据)。