Qdrant 集群模式部署指南

Qdrant v1.15.3 三节点分布式集群部署指南:Raft 共识与分片副本原理、--uri/--bootstrap 顺序启动拉齐、建复制集合同写一致性验证、节点故障转移与自动回补,覆盖配置文件与系统d 全部流程

QdrantQdrant向量数据库集群systemd 托管向量NoSQL2026/10/02

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 中配置三件事:

  1. cluster.enabled: true —— 开启集群模式;
  2. cluster.p2p.port: 6335 —— 节点间 gossip/Raft 通信端口;
  3. 启动参数:首节点用 --uri 声明自身地址,后续节点用 --bootstrap 加入首节点(详见第五节)。
cluster:
  enabled: true
  p2p:
    port: 6335

二、环境与 IP 规划

主机名内网 IP角色
qdrant-node1192.168.100.11首个引导节点(bootstrapper),用自己的 --uri 声明地址
qdrant-node2192.168.100.12通过 --bootstrap 加入 node1
qdrant-node3192.168.100.13通过 --bootstrap 加入 node1

端口规划:

端口用途
6333HTTP REST API
6334gRPC
6335P2P(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.statusenabled
result.peers含 3 个节点(node1/2/3)
result.raft_info.leader某个节点 uuid,即当前 Leader
result.raft_info.roleLeader(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,并只针对确实损坏的节点执行。

十、常见问题

  1. 集群状态不是 enabled,或 peers 只有自己 检查 cluster.enabled: true 与 cluster.p2p.port: 6335 是否配置;确认 6335 端口在防火墙放行;确认 --uri/--bootstrap 指向的是 P2P 端口 6335。

  2. 后续节点一直加入不进来 首节点必须已用 --uri 启动并成为 Leader(等待约 4 秒 consensus)后才可被 bootstrap;按「node1 → node2 → node3」顺序,不要并发同时启动。

  3. 写请求被拒,提示集合不可用 / consistency 不满足 write_consistency_factor 不能高于当前存活副本数。副本 2/3 存活时仍可写(因子 ≤2);副本不足该值时需等待副本恢复或调低因子。

  4. count 在各节点不一致 确认写请求返回的是 acknowledged 而非 enqueued/拒绝;等待副本同步;用 exact: true 的 count 并配合集群拓扑校验。

  5. 节点自访问瞬时 refused 节点间调用改用 hostname/DNS(写进 /etc/hosts)而非 IP 直连,最稳定(实测经验)。

  6. 共识 WAL 不断增长 检查 cluster.consensus.compact_wal_entries(如 128)是否生效,必要时调小触发值。

  7. 节点重启后 peer 仍显示离线 等待节点 catch-up 完成即可;若长时间未恢复且共识状态损坏,按第九节用 --reinit 恢复。

  8. 卸载某台节点 先 sudo systemctl disable --now qdrant,再清理 /opt/qdrant、/etc/qdrant、/storage/qdrant(谨慎,会删数据)。

Qdrant 集群模式部署指南 - Quzuo