Doramagic 项目包 · 项目说明书
qdrant 项目
生成时间:2026-05-31 03:33:46 UTC
Qdrant 简介
Qdrant(发音为 "quadrant")是一个高性能的向量相似度搜索引擎和向量数据库,采用 Rust 语言编写,使其在高压负载下依然保持出色的性能和可靠性。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
项目概述
Qdrant(发音为 "_quadrant_")是一个高性能的向量相似度搜索引擎和向量数据库,采用 Rust 语言编写,使其在高压负载下依然保持出色的性能和可靠性。
Qdrant 提供生产级的服务能力和便捷的 API,用于存储、搜索和管理 points——即带有额外 payload(负载)的向量。通过扩展的过滤支持,Qdrant 特别适用于各类神经网络匹配、语义匹配、分面搜索等应用场景。资料来源:README.md:1
核心特性
| 特性 | 描述 |
|---|---|
| 向量搜索 | 高效的近似最近邻(ANN)搜索 |
| 过滤支持 | 强大的分面过滤能力 |
| 多种距离度量 | 支持 Cosine、Dot Product、Euclidean、Manhattan 等 |
| 客户端库 | 提供 Python、JavaScript/TypeScript、.NET/C#、Java、PHP 等多语言客户端 |
| Qdrant Edge | 轻量级边缘设备版本,支持嵌入式运行 |
资料来源:README.md:1-50
系统架构
Qdrant 采用分层架构设计,核心组件协同工作以提供完整的向量搜索能力。
整体架构图
graph TB
subgraph "客户端层"
Client[多语言客户端]
end
subgraph "服务层 /src"
API[REST API]
HTTP[HTTP Client]
Telemetry[遥测模块]
Auth[认证模块]
end
subgraph "集合层 /lib/collection"
Collection[Collection]
Shards[分片管理]
WAL[Write-Ahead Log]
Discovery[发现模块]
end
subgraph "分片层 /lib/shard"
SegmentHolder[Segment Holder]
ProxySegment[代理分片]
Operations[操作模块]
Optimizers[优化器]
end
subgraph "段层 /lib/segment"
HNSW[HNSW 索引]
VectorStorage[向量存储]
PayloadIndex[Payload 索引]
IdTracker[ID 追踪器]
end
subgraph "存储层"
GridStore[GridStore]
MemoryMap[内存映射]
end
Client --> API
API --> Collection
Collection --> Shards
Shards --> SegmentHolder
SegmentHolder --> HNSW
SegmentHolder --> VectorStorage
Collection --> WAL
HNSW --> MemoryMap
VectorStorage --> GridStore核心模块说明
#### 服务层(src/common/)
服务层负责处理外部请求、系统监控和运维功能。资料来源:src/common/mod.rs:1-25
| 模块 | 功能 |
|---|---|
auth | 认证和授权 |
collections | 集合管理 |
health | 健康检查 |
http_client | HTTP 客户端封装 |
metrics | 指标收集 |
telemetry | 遥测数据上报 |
snapshots | 快照管理 |
validation | 输入验证 |
#### 集合层(lib/collection/)
集合层是 Qdrant 的核心数据组织单元,负责集合级别的操作和状态管理。资料来源:lib/collection/src/lib.rs:1-25
graph LR
subgraph "Collection Operations"
Update[更新操作]
Query[查询操作]
Config[配置管理]
end
subgraph "Collection Management"
ShardManager[分片管理器]
OptimizerBuilder[优化器构建器]
UpdateHandler[更新处理器]
end
Update --> ShardManager
Query --> ShardManager
Config --> OptimizerBuilder
ShardManager --> UpdateHandler#### 分片层(lib/shard/)
分片层管理 segments 的生命周期和数据分片策略。资料来源:lib/shard/src/lib.rs:1-35
| 组件 | 职责 |
|---|---|
segment_holder | 管理多个 segments |
proxy_segment | 分片代理,拦截读写操作 |
locked_segment | 线程安全的分片访问 |
wal | Write-Ahead Log 持久化 |
snapshots | 分片快照管理 |
update | 更新操作处理 |
#### 段层(lib/segment/)
段(Segment)是 Qdrant 中数据存储和索引的基本单元。资料来源:lib/segment/src/lib.rs:1-20
| 数据类型模块 | 说明 |
|---|---|
index | 索引构建和查询 |
vector_storage | 向量数据存储 |
payload_storage | Payload 数据存储 |
id_tracker | 点 ID 追踪 |
spaces | 空间度量计算 |
数据模型
Point 结构
Qdrant 中的基本数据单元是 Point,每个 Point 包含:
graph TB
Point["Point (点)"]
Vector["Vector (向量)"]
Payload["Payload (负载)"]
Id["ID (唯一标识)"]
Point --> Id
Point --> Vector
Point --> Payload
Vector --> MultiVector["多向量支持"]
Payload --> KeyValue["键值对"]| 字段 | 类型 | 描述 |
|---|---|---|
id | u64/string | 点的唯一标识符 |
vector | f32[]/f32[][] | 向量数据,支持单个或多个向量 |
payload | JSON Object | 可选的元数据负载 |
向量存储类型
资料来源:lib/segment/src/data_types/mod.rs:1-15
Qdrant 支持多种向量存储配置:
| 存储类型 | 用途 |
|---|---|
| 稀疏向量 | 高维稀疏数据 |
| 密集向量 | 标准密集嵌入 |
| 多向量 | ColBERT 等晚期交互模型 |
索引机制
HNSW 索引
HNSW(Hierarchical Navigable Small World)是 Qdrant 默认的向量索引算法,提供高效的近似最近邻搜索能力。资料来源:lib/segment/src/index/mod.rs
graph TD
Start[查询入口] --> L3[Layer 3 (顶层)]
L3 --> L2[Layer 2]
L2 --> L1[Layer 1]
L1 --> L0[Layer 0 (底层)]
L0 --> Result[最近邻结果]
L3 -.-> Skip["跳层搜索"]
L2 -.-> Skip
L1 -.-> Skip量化支持
Qdrant 提供多种量化选项以平衡精度和性能:
| 量化类型 | 压缩比 | 精度损失 | 适用场景 |
|---|---|---|---|
| Scalar | 4× | 低 | 通用场景 |
| Product Quantization (PQ) | 可配置 | 中 | 大规模数据 |
| Binary | 高 | 高 | 仅限 1024d+ |
| TurboQuant | 可配置 | 低 | ICLR 2026 新特性 |
社区关注:TurboQuant 是社区重点关注的新量化方案(#8524),设计文档位于 Notion,追踪 issue 为 #8670。
存储层
GridStore
GridStore 是 Qdrant 的高性能存储引擎,用于替代传统的 RocksDB,提供更好的随机读写性能。资料来源:lib/gridstore/src/pages.rs:1-80
graph LR
subgraph "GridStore 架构"
Pages["Pages (页面管理)"]
Flush["Flusher (刷新机制)"]
MMap["Memory Map (内存映射)"]
end
Write["写入请求"] --> Pages
Pages --> Flush
Flush --> MMap内存映射
Qdrant 大量使用内存映射(mmap)技术优化大文件访问:
| 功能 | 描述 |
|---|---|
will_need | 预读数据到页缓存 |
populate | 填充页缓存 |
pageout | Linux 页面换出 |
资料来源:lib/common/common/src/mmap/advice.rs:1-60
客户端与 API
多语言客户端
Qdrant 提供官方维护的多语言客户端库:
| 语言 | 仓库 |
|---|---|
| Python | qdrant-client |
| JavaScript/TypeScript | qdrant-js |
| .NET/C# | qdrant-dotnet |
| Java | java-client |
| PHP | qdrant-php (社区维护) |
REST API
Qdrant 提供完整的 RESTful API 用于所有操作。资料来源:lib/api/src/rest/mod.rs:1-10
| API 端点 | 方法 | 功能 |
|---|---|---|
/collections/{name}/points/search | POST | 向量搜索 |
/collections/{name}/points/scroll | POST | 分页浏览 |
/collections/{name}/points | PUT/DELETE | 点的增删 |
/collections | GET/POST | 集合管理 |
Qdrant Edge
Qdrant Edge 是专为边缘设备和资源受限环境设计的轻量级版本。与客户端-服务器架构的 Qdrant Server 不同,Qdrant Edge 运行在应用程序进程内部。
graph TB
subgraph "Qdrant Server (服务端)"
ServerAPI[REST API]
ServerStorage[持久化存储]
end
subgraph "Qdrant Edge (嵌入式)"
EdgeLib[Edge Library]
LocalStorage[本地存储]
Sync[数据同步]
end
EdgeLib --> Sync
Sync <--> ServerAPI
EdgeLib --> LocalStorage
ServerAPI --> ServerStorage快速开始示例
from qdrant_edge import Distance, EdgeConfig, EdgeVectorParams, EdgeShard, Point, UpdateOperation
shard = EdgeShard.create("./shard", EdgeConfig(
vectors={"my-vector": EdgeVectorParams(size=4, distance=Distance.Cosine)}
))
shard.update(UpdateOperation.upsert_points([
Point(id=1, vector={"my-vector": [0.1, 0.2, 0.3, 0.4]}, payload={"color": "red"})
]))
资料来源:README.md:40-55
版本与发布
最新版本:v1.18.1
| 类别 | 更新内容 |
|---|---|
| 改进 | 重构量化多向量评分器以支持 io_uring |
| 改进 | 异步 upsert 前验证向量维度 |
| 修复 | 快照应用时通知待处理共识操作 |
历史版本要点
| 版本 | 主要特性 |
|---|---|
| v1.17.1 | GridStore 刷新非阻塞化,减少搜索尾延迟 |
| v1.17.0 | 相关性反馈功能、详细优化进度 API |
| v1.16.x | 批处理优化、遥测超时改进、WAL 关键修复 |
已知问题与限制
社区关注的问题
| Issue | 描述 | 状态 |
|---|---|---|
| #1132 | 创建集合后无法添加新向量字段 | 开放 |
| #2550 | 删除点后应标记向量为已删除 | 开放 |
| #8524 | TurboQuant 量化方案 | 开发中 |
| #3684 | ColBERT 晚期交互模型支持 | 开发中 |
测试稳定性
近期发现多个量化搜索相关的测试存在不稳定性,主要涉及:
hnsw_quantized_search_test::hnsw_turbo_quantization_*系列测试hnsw_discover_test::filtered_hnsw_discover_precision
这些问题主要表现为测试中断言失败 best_2.score >= best_1.score,相关 issue 包括 #8735、#8801、#8806、#8834、#8835、#8906、#8704。
技术栈总结
| 层级 | 技术/语言 |
|---|---|
| 核心引擎 | Rust |
| 存储引擎 | GridStore + Memory Map |
| 索引算法 | HNSW + 多种量化方案 |
| 通信协议 | REST (OpenAPI 3.0) |
| 部署方式 | 独立服务器 / 嵌入式 (Edge) |
Qdrant 通过 Rust 语言的优势实现了高性能、低内存占用的向量搜索服务,同时提供丰富的客户端库和完整的 API 支持,满足从研究实验到生产部署的各种场景需求。
资料来源:README.md:1-50
核心概念
Qdrant 是一个高性能的向量相似度搜索引擎,其架构围绕几个核心概念构建:集合(Collection)、分片(Shard)、段(Segment)以及存储层。这些概念共同构成了 Qdrant 的数据存储和检索体系。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
数据模型层级结构
Qdrant 采用分层架构来组织和管理向量数据,从宏观的集合到微观的点(Point),形成了清晰的数据层级。
graph TD
A[Collection 集合] --> B[Shard 分片]
B --> C[Segment 段]
C --> D[Point 点]
D --> E[Vector 向量]
D --> F[Payload 负载]点(Point)
点是 Qdrant 中最基本的数据单元,包含向量数据和可选的负载信息。每个点由唯一标识符、向量和负载组成。
graph LR
A[Point ID] --> D
B[Vector] --> D
C[Payload] --> D
D[Point]从源码中可以看到数据类型的组织结构:
// lib/segment/src/data_types/mod.rs
pub mod build_index_result;
pub mod collection_defaults;
pub mod facets;
pub mod groups;
pub mod index;
pub mod manifest;
pub mod modifier;
pub mod named_vectors;
pub mod order_by;
pub mod primitive;
pub mod query_context;
pub mod segment_record;
pub mod tiny_map;
pub mod vector_name_config;
pub mod vectors;
资料来源:lib/segment/src/data_types/mod.rs:1-18
集合(Collection)
集合是顶层的命名空间,用于组织相关的向量数据。每个集合拥有独立的配置,包括向量维度、距离度量方式和优化器参数。
Collection 配置结构
集合配置存储在 config.rs 中,支持多种可自定义的元数据:
// lib/collection/src/config.rs
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<Payload>,
配置通过原子文件(Atomic File)机制进行持久化:
impl CollectionConfigInternal {
pub fn save(&self, path: &Path) -> CollectionResult<()> {
let config_path = path.join(COLLECTION_CONFIG_FILE);
let af = AtomicFile::new(&config_path, AllowOverwrite);
// ...
}
pub fn load(path: &Path) -> CollectionResult<Self> {
let config_path = path.join(COLLECTION_CONFIG_FILE);
// ...
}
}
资料来源:lib/collection/src/config.rs:1-50
集合模块组成
集合模块位于 lib/collection/src/lib.rs,包含以下核心子模块:
| 模块名称 | 功能描述 |
|---|---|
| collection | 集合管理核心逻辑 |
| collection_manager | 集合级别的资源管理 |
| collection_state | 集合状态追踪 |
| config | 配置管理 |
| discovery | 发现查询功能 |
| grouping | 分组查询 |
| hash_ring | 一致性哈希环(分片路由) |
| recommendations | 推荐系统功能 |
| shards | 分片管理 |
| operations | 集合操作(通用化接口) |
| optimizers_builder | 优化器构建器 |
| wal_delta | WAL 增量管理 |
资料来源:lib/collection/src/lib.rs:1-30
分片(Shard)
分片是集合数据的水平分区单元,用于实现分布式存储和查询负载均衡。
graph TD
subgraph Collection
A[Shard 1] --> D[Segment 1.1]
A --> E[Segment 1.2]
B[Shard 2] --> F[Segment 2.1]
B --> G[Segment 2.2]
C[Shard N] --> H[Segment N.1]
C --> I[Segment N.2]
end分片模块结构
分片模块在 lib/shard/src/lib.rs 中定义:
pub mod common;
pub mod count;
pub mod facet;
pub mod files;
pub mod locked_segment;
pub mod operation_rate_cost;
pub mod operations;
pub mod optimize;
pub mod optimizers;
pub mod payload_index_schema;
pub mod proxy_segment;
pub mod query;
pub mod retrieve;
pub mod scroll;
pub mod search;
pub mod search_result_aggregator;
pub mod segment_holder;
pub mod snapshots;
pub mod tracker;
pub mod update;
pub mod wal;
资料来源:lib/shard/src/lib.rs:1-30
每个分片包含以下核心组件:
| 组件 | 功能 |
|---|---|
| segment_holder | 持有多个段,管理段的注册和注销 |
| wal | 预写日志,确保数据持久性 |
| update | 更新操作处理 |
| query | 查询执行引擎 |
| optimizers | 段合并和优化任务 |
| snapshots | 分片快照管理 |
段(Segment)
段是存储和索引向量数据的基本单元,是 HNSW 索引等数据结构的具体载体。
Segment 模块结构
段模块位于 lib/segment/src/lib.rs:
pub mod common;
pub mod entry;
#[cfg(feature = "testing")]
pub mod fixtures;
pub mod id_tracker;
pub mod index;
pub mod payload_storage;
pub mod segment;
pub mod segment_constructor;
pub mod spaces;
pub mod telemetry;
mod compat;
pub mod data_types;
pub mod json_path;
pub mod types;
pub mod utils;
pub mod vector_storage;
资料来源:lib/segment/src/lib.rs:1-20
索引类型
段支持多种索引类型,用于加速不同场景的查询:
- HNSW 索引:层次可导航小世界图,是向量相似度搜索的主要索引结构
- 全文索引:支持文本字段的全文检索,包含中文停用词支持
- 条件索引:基于负载字段的条件过滤
段的生命周期
stateDiagram-v2
[*] --> Mutable: 创建新段
Mutable --> Immutable: 触发 flush
Immutable --> Optimizing: 优化器调度合并
Optimizing --> [*]: 合并完成
Mutable --> [*]: 删除操作GridStore 存储层
GridStore 是 Qdrant 的核心存储引擎,替代了传统的 RocksDB,提供更高效的 I/O 操作。
GridStore 配置
GridStore 的默认配置参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
| page_size_bytes | 32MB | 页大小 |
| block_size_bytes | 128 bytes | 块大小 |
| region_size_blocks | 8192 blocks | 区域大小 |
| compression | LZ4 | 压缩算法 |
资料来源:lib/gridstore/src/config.rs:1-40
页面管理机制
GridStore 使用基于页面的存储架构,支持高效的写入和读取操作:
// lib/gridstore/src/pages.rs
impl<S: UniversalWrite> Pages<S> {
pub fn write_to_pages(
&mut self,
pointer: ValuePointer,
value: &[u8],
config: &StorageConfig,
) -> Result<()> {
// 跨页写入处理
let writes = Self::get_page_value_ranges(pointer, config)
.map(|(buf_offset, page, range)| {
let data = &value[buf_offset..buf_offset + range.length as usize];
(page as FileIndex, range.byte_offset, data)
});
S::write_multi(self.pages.as_mut_slice(), writes)?;
Ok(())
}
}
资料来源:lib/gridstore/src/pages.rs:1-100
非阻塞刷新
v1.17.1 版本的重要改进是 GridStore 刷新操作改为非阻塞模式,显著降低了搜索尾延迟。
相关社区讨论:多个用户报告了量化搜索相关的测试不稳定问题,涉及 HNSW 量化搜索测试中分数比较断言失败的情况。
预写日志(WAL)
预写日志是确保数据持久性的关键机制,即使在系统崩溃后也能恢复数据。
WAL 关键特性
- 原子性保证:更新操作先写入 WAL,再应用到内存结构
- 崩溃恢复:重启时从 WAL 重放未刷新的操作
- 一致性检查:v1.16.2 版本修复了可能导致共识破坏的 WAL 关键 bug
社区关注:WAL 相关的 bug 修复是 v1.16.2 版本的重要安全修复。
量化技术
Qdrant 支持多种量化方法来压缩向量存储空间:
| 量化类型 | 压缩比 | 适用场景 | 限制 |
|---|---|---|---|
| Scalar | 4x | 通用场景 | 维度需足够大 |
| Binary | 高 | 超低维度 | 维度 < 1024d 效果差 |
| PQ | 可配置 | 极致压缩 | 需要训练码本 |
| TurboQuant | 极高 | 激进压缩 | ICLR 2026 新特性 |
社区热点:TurboQuant 量化是社区关注的重点功能,设计文档在 Notion 中公开。
资料来源:Issue #8524
存储配置示例
Qdrant 的存储行为可通过 config.yaml 灵活配置:
storage:
storage_path: ./storage
snapshots_path: ./snapshots
temp_path: null
on_disk_payload: true # 负载数据是否落盘
# 其他优化参数...
异步 I/O 与性能优化
Qdrant 利用现代 Linux 的 io_uring 特性实现高效的异步 I/O,即使在网络存储上也能最大化磁盘吞吐量。
批处理优化
v1.16.1 版本引入的批处理优化使全量扫描查询速度提升高达 3 倍,原理是每个点只读取一次:
相关 PR:Make batch queries up to 3 times faster on full scans by reading each point only once
内存映射优化
系统页面大小对内存映射操作有重要影响:
// lib/common/common/src/mmap/advice.rs
#[cfg(unix)]
fn get_page_size() -> Result<usize, String> {
let page_size = nix::unistd::sysconf(nix::unistd::SysconfVar::PAGE_SIZE)
.map_err(|err| format!("Failed to get page size: {err}"))?
.ok_or_else(|| "sysconf(PAGE_SIZE) returned None".to_string())?;
// 通常 x86_64 为 4096,aarch64 macOS 为 16384
}
资料来源:lib/common/common/src/mmap/advice.rs:1-30
关键设计决策
多租户支持
Qdrant 的 hash_ring 模块实现了一致性哈希,用于在多个节点间分配分片,支持大规模多用户环境。
延迟物化
v1.17.0 版本引入的相关性反馈(Relevance Feedback)功能允许用户标记搜索结果的相关性,从而优化后续查询的排序。
新功能:Relevance Feedback API 为用户提供了细粒度的结果相关性反馈机制。
延迟更新优化
v1.17.1 版本通过 prevent_unoptimized=true 参数实现延迟点更新优化,避免频繁的小更新导致的性能抖动。
概念关系总览
graph TD
subgraph 客户端层
A[REST API / gRPC]
end
subgraph 集合层
B[Collection] --> C[CollectionConfig]
B --> D[Hash Ring]
end
subgraph 分片层
D --> E[Shard 1]
D --> F[Shard 2]
D --> G[Shard N]
end
subgraph 段层
E --> H[Segment Holder]
H --> I[Mutable Segment]
H --> J[Immutable Segment]
I --> K[HNSW Index]
I --> L[Vector Storage]
I --> M[Payload Storage]
end
subgraph 存储层
L --> N[GridStore]
M --> N
N --> O[WAL]
N --> P[Disk Files]
end
A --> B总结
Qdrant 的核心概念构成了一个层次分明、高度模块化的向量数据库架构:
- 集合作为顶层命名空间,提供独立配置和隔离的数据空间
- 分片实现水平扩展,通过一致性哈希进行数据分布
- 段是数据存储和索引的基本单元,支持多种索引类型
- GridStore提供高性能的持久化存储,支持压缩和非阻塞 I/O
- WAL确保数据可靠性和崩溃恢复能力
这些概念相互协作,共同支撑 Qdrant 作为生产级向量搜索引擎的各项能力,包括高性能相似度搜索、灵活的过滤查询、分布式部署和数据持久化保证。
系统架构
Qdrant 是一个用 Rust 编写的向量相似度搜索引擎,采用模块化架构设计,支持高维向量数据的存储、索引和高效相似度检索。本页面详细介绍 Qdrant 的核心架构组件及其交互关系。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
整体架构概览
Qdrant 采用分层架构,从上到下依次为:API 层、集合管理层、分片层、Segment 层和存储层。各层之间通过清晰的接口定义进行通信,实现了关注点分离和模块化设计。
graph TD
subgraph API层
REST_API[REST API]
gRPC_API[gRPC API]
end
subgraph 集合管理层
Collection[Collection Manager]
Config[Collection Config]
end
subgraph 分片层
Shard[Shard]
ProxySegment[Proxy Segment]
SegmentHolder[Segment Holder]
end
subgraph Segment层
Segment[Segment]
HNSW[HNSW Index]
PayloadIndex[Payload Index]
VectorStorage[Vector Storage]
end
subgraph 存储层
GridStore[GridStore]
RocksDB[RocksDB]
WAL[Write-Ahead Log]
end
REST_API --> Collection
gRPC_API --> Collection
Collection --> Shard
Shard --> SegmentHolder
SegmentHolder --> Segment
Segment --> HNSW
Segment --> PayloadIndex
Segment --> VectorStorage
Segment --> WAL
VectorStorage --> GridStore
PayloadIndex --> RocksDB核心模块
API 层
API 层负责处理外部请求,包括 REST API 和 gRPC API 两种接口形式。REST API 提供 OpenAPI 规范的 HTTP 接口,用于与客户端进行交互。
集合管理层 (Collection)
Collection 是 Qdrant 中的核心管理单元,负责管理整个集合的元数据、配置和操作。Collection 模块包含以下主要组件:
| 组件 | 说明 |
|---|---|
collection.rs | 集合的核心实现,处理集合级别的操作 |
config.rs | 集合配置管理,包括向量维度、索引参数等 |
operations/ | 集合操作模块,包括 CRUD、搜索、更新等 |
collection_state.rs | 集合状态管理 |
shards.rs | 分片管理 |
集合配置通过 CollectionConfigInternal 结构体管理,支持存储应用级别的元数据信息,如创建时间、迁移数据和推理模型信息等。
资料来源:lib/collection/src/lib.rs:1-29
分片层 (Shard)
Shard 层实现分布式数据分片,支持数据水平扩展。每个 Shard 包含多个 Segment,并通过 Hash Ring 机制实现数据分片路由。
graph LR
HashRing[Hash Ring Router]
HashRing -->|Shard 0| S0[Shard 0]
HashRing -->|Shard 1| S1[Shard 1]
HashRing -->|Shard 2| S2[Shard 2]
S0 --> SH0[Segment Holder]
S1 --> SH1[Segment Holder]
S2 --> SH2[Segment Holder]
SH0 --> Seg1[Segment]
SH0 --> Seg2[Segment]
SH1 --> Seg3[Segment]
SH2 --> Seg4[Segment]
SH2 --> Seg5[Segment]分片操作通过 SplitByShard trait 实现,支持将操作按照 Hash Ring 路由到对应的分片:
impl SplitByShard for CollectionUpdateOperations {
fn split_by_shard(self, ring: &HashRingRouter) -> OperationToShard<Self>
资料来源:lib/shard/src/lib.rs:1-40
Segment 层
Segment 是 Qdrant 中数据存储和索引的基本单元。每个 Segment 包含向量数据、Payload 数据和各类索引结构。
| 模块 | 说明 |
|---|---|
segment.rs | Segment 核心实现 |
index/hnsw_index/ | HNSW 近似最近邻索引 |
payload_storage/ | Payload 存储管理 |
vector_storage/ | 向量存储管理 |
segment_constructor/ | Segment 构造器 |
spaces/ | 距离空间定义 |
资料来源:lib/segment/src/lib.rs:1-18
#### Segment 数据一致性检查
Segment 提供 check_data_consistency 方法用于检查数据一致性,该方法检测以下几种不一致情况:
- 内部 ID 无对应的外部 ID
- 外部 ID 无对应的内部 ID
- 内部 ID 无对应的版本信息
- 内部 ID 无对应的向量数据
资料来源:lib/segment/src/segment/segment_ops.rs:200-230
存储层
#### GridStore
GridStore 是 Qdrant 新一代存储引擎,用于替代 RocksDB。它采用分页式存储架构,优化了向量数据的读写性能。
| 配置项 | 默认值 | 说明 |
|---|---|---|
page_size_bytes | 32MB | 页面大小 |
block_size_bytes | 128 bytes | 块大小 |
region_size_blocks | 8192 | 区域块数 |
compression | LZ4 | 压缩算法 |
GridStore 的页面管理通过 Pages<S> 结构体实现,支持多页面写入和数据指针管理。当数据跨页存储时,系统会自动处理页面边界的读写操作。
资料来源:lib/gridstore/src/config.rs:1-80
#### Write-Ahead Log (WAL)
WAL 确保数据持久性,即使在系统故障情况下也能保证更新确认。每个 Segment 都有自己的 WAL,通过日志机制实现数据恢复。
操作流程
写入流程
sequenceDiagram
participant Client
participant API
participant Collection
participant Shard
participant Segment
participant WAL
participant GridStore
Client->>API: 上传向量数据
API->>Collection: PointOperation
Collection->>Shard: SplitByShard
Shard->>Segment: 写入操作
Segment->>WAL: 写入日志
Segment->>GridStore: 写入数据
GridStore-->>Segment: 写入确认
WAL-->>Segment: 日志确认
Segment-->>Shard: 操作完成
Shard-->>Collection: 操作完成
Collection-->>API: 操作完成
API-->>Client: 成功响应搜索流程
sequenceDiagram
participant Client
participant API
participant Collection
participant Shard
participant SegmentHolder
participant Segment
participant HNSW
Client->>API: 搜索请求
API->>Collection: Search Request
Collection->>Shard: 广播到所有分片
Shard->>SegmentHolder: 获取所有 Segment
SegmentHolder->>Segment: 并行搜索
Segment->>HNSW: HNSW 近似搜索
HNSW-->>Segment: Top-K 结果
Segment-->>Shard: 分片结果
Shard-->>Collection: 聚合结果
Collection-->>API: 最终结果
API-->>Client: 返回结果配置管理
集合配置
集合配置通过 CollectionConfigInternal 结构体管理,支持以下功能:
- 持久化存储配置
- 运行时加载配置
- 配置验证和警告
impl CollectionConfigInternal {
pub fn save(&self, path: &Path) -> CollectionResult<()>;
pub fn load(path: &Path) -> CollectionResult<Self>;
pub fn check(path: &Path) -> bool;
}
资料来源:lib/collection/src/config.rs:1-70
遥测与可观测性
Qdrant 提供全面的遥测系统,用于监控集群健康状况和性能指标。
| 模块 | 说明 |
|---|---|
app_telemetry | 应用级遥测 |
cluster_telemetry | 集群状态遥测 |
collections_telemetry | 集合级别遥测 |
hardware | 硬件指标 |
memory_telemetry | 内存使用情况 |
requests_telemetry | 请求指标 |
distributed_telemetry | 分布式相关遥测 |
资料来源:src/common/telemetry_ops/mod.rs:1-15
优化机制
分批查询优化
Qdrant 在 v1.16.1 版本中优化了分批查询性能,通过单次读取每个向量数据,使全表扫描的分批查询速度提升至原来的 3 倍。
GridStore 迁移
系统启动时,Qdrant 会主动将向量、Payload 和 Payload 索引存储从 RocksDB 迁移到 GridStore,以提高整体性能。
非阻塞刷新
在 v1.17.1 版本中,GridStore 的刷新操作改为非阻塞模式,有效降低了搜索尾延迟。
相关社区问题
以下社区问题涉及 Qdrant 架构相关的功能改进和已知限制:
| Issue | 说明 | 优先级 |
|---|---|---|
| #8524 | TurboQuant 量化技术,支持更激进的压缩比 | 高 |
| #3684 | ColBERT 晚期交互模型集成 | 中 |
| #2550 | 删除点时同时删除向量标记 | 中 |
| #1132 | 集合创建后添加新向量字段 | 中 |
版本演进
| 版本 | 主要改进 |
|---|---|
| v1.18.1 | 量化多向量评分器重构支持 io_uring |
| v1.17.1 | 非阻塞 GridStore 刷新,延迟点更新优化 |
| v1.17.0 | Relevance Feedback 功能,优化进度报告 API |
| v1.16.3 | 搜索和检索超时处理改进 |
| v1.16.2 | 遥测和指标请求超时处理 |
| v1.16.1 | 分批查询性能提升,GridStore 启动迁移 |
集合管理
集合(Collection)是 Qdrant 中管理和组织向量数据的基本单元。本页面详细说明集合管理的架构设计、核心组件、配置选项以及操作流程。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Qdrant 的集合管理系统负责以下核心职责:
- 创建、删除和配置向量集合
- 管理集合内的向量数据和负载(Payload)
- 处理集合级别的查询操作
- 维护集合状态和元数据
- 支持分片(Sharding)实现水平扩展
集合管理的核心代码位于 lib/collection 目录,采用模块化设计以支持不同类型的向量存储和查询操作。资料来源:lib/collection/src/lib.rs:1-27
核心架构
模块层次结构
集合管理系统的模块结构如下:
graph TD
A[集合管理层] --> B[lib/collection]
A --> C[lib/shard]
A --> D[lib/segment]
B --> B1[collection]
B --> B2[collection_manager]
B --> B3[collection_state]
B --> B4[config]
B --> B5[operations]
B --> B6[shards]
B --> B7[optimizers_builder]
C --> C1[segment_holder]
C --> C2[operations]
C --> C3[wal]
C --> C4[update]核心组件
| 组件 | 文件位置 | 职责 |
|---|---|---|
| Collection | lib/collection/src/collection/mod.rs | 集合主类,处理核心业务逻辑 |
| CollectionManager | lib/collection/src/collection_manager/ | 管理多个集合的生命周期 |
| CollectionState | lib/collection/src/collection_state/ | 维护集合运行时状态 |
| Shard | lib/shard/src/lib.rs | 管理分片数据和复制 |
| Segment | lib/segment/src/segment/ | 底层数据存储和索引 |
资料来源:lib/collection/src/lib.rs:1-27
集合配置
配置结构
集合配置通过 CollectionConfigInternal 结构体管理,包含以下关键配置项:
- 向量参数(VectorParams):向量维度、距离度量、稀疏向量配置
- 负载索引(PayloadIndexSchema):负载字段索引定义
- 优化器配置(OptimizerConfig):HNSW 和量化参数
- 元数据(metadata):应用特定信息,如创建时间、迁移数据等
pub struct CollectionConfigInternal {
pub metadata: Option<Payload>, // 可选的应用元数据
}
资料来源:lib/collection/src/config.rs:1-50
配置持久化
集合配置支持序列化存储和加载:
| 方法 | 功能 |
|---|---|
to_bytes() | 将配置序列化为字节数组 |
save(path) | 使用原子写入保存配置到文件 |
load(path) | 从文件加载并反序列化配置 |
check(path) | 检查配置文件是否存在 |
pub fn save(&self, path: &Path) -> CollectionResult<()> {
let config_path = path.join(COLLECTION_CONFIG_FILE);
let af = AtomicFile::new(&config_path, AllowOverwrite);
// 使用原子写入确保数据一致性
}
pub fn load(path: &Path) -> CollectionResult<Self> {
// 从 JSON 文件读取并解析
}
资料来源:lib/collection/src/config.rs:30-50
分片管理
分片架构
Qdrant 使用分片实现水平扩展,集合数据分布在多个分片上:
graph LR
A[Collection] --> B[Shard 1]
A --> C[Shard 2]
A --> D[Shard N]
B --> E[Segment 1]
B --> F[Segment 2]
C --> G[Segment 1]
C --> H[Segment 2]
D --> I[Segment 1]
D --> J[Segment 2]分片操作接口
| 操作 | 描述 |
|---|---|
| PointOperation | 点操作(插入、更新、删除) |
| VectorOperation | 向量操作(添加、删除向量字段) |
| PayloadOperation | 负载操作(设置、删除、修改负载字段) |
pub trait SplitByShard {
fn split_by_shard(self, ring: &HashRingRouter) -> OperationToShard<Self>
where Self: Sized;
}
资料来源:lib/collection/src/operations/mod.rs:35-60
负载索引管理
集合支持为负载字段创建索引以加速过滤查询:
pub fn create_field_index(
&self,
version: SeqNumberType,
key: PayloadKeyType,
schema: Option<FieldIndexSchema>,
counter: &HardwareCounterCell,
) -> OperationResult<bool>;
负载索引类型包括:
- 整数索引:用于整数类型字段
- 字符串索引:用于文本匹配查询
- 地理位置索引:用于地理范围查询
- 布尔索引:用于布尔值过滤
索引创建时会检查现有配置,如果不匹配会重新创建。资料来源:lib/segment/src/segment/segment_ops.rs:1-100
数据通用化
Generalizer 特性
集合操作支持通用化(Generalization)接口,用于在日志记录、审计和脱敏场景中移除敏感数据:
pub trait Generalizer {
fn remove_details(&self) -> Self;
}
通用化处理规则:
- 向量数据替换为长度信息
- 负载数据替换为键和长度信息
- 其他字段完整保留
资料来源:lib/collection/src/operations/generalizer/mod.rs:1-20
操作类型
查询操作
| 操作类型 | 描述 |
|---|---|
| Search | 近似最近邻搜索 |
| Recommend | 基于向量的推荐 |
| Discover | 发现查询 |
| Scroll | 分页滚动查询 |
| Count | 计数查询 |
| Aggregate | 聚合查询 |
更新操作
| 操作类型 | 描述 |
|---|---|
| Upsert | 插入或更新点 |
| Delete | 删除点 |
| UpdateVectors | 更新向量 |
| SetPayload | 设置负载 |
| DeletePayload | 删除负载 |
资料来源:lib/collection/src/operations/mod.rs:10-40
集合状态管理
状态检查
集合提供数据一致性检查功能:
pub fn check_data_consistency(&self) -> OperationResult<()>
检查项目包括:
- 内部 ID 存在但外部 ID 不存在
- 外部 ID 存在但内部 ID 不存在
- 内部 ID 存在但版本信息不存在
- 内部 ID 存在但向量数据不存在
注意:单个分片可能包含不一致的段,但由于点是基于版本合并的,整个分片仍可保持一致性。
资料来源:lib/segment/src/segment/segment_ops.rs:80-100
相关社区问题
热点问题
| Issue | 描述 | 状态 |
|---|---|---|
| #1132 | 集合创建后添加新向量字段 | 开放 |
| #2550 | 删除点时同时删除向量 | 开放 |
| #3684 | ColBERT 延迟交互模型支持 | 进行中 |
Issue #1132 反映了用户对在集合创建后动态添加新向量字段的需求,这是当前集合管理的一个重要限制。资料来源:社区 Issue #1132
版本演进
| 版本 | 改进内容 |
|---|---|
| v1.17.1 | 使用 prevent_unoptimized=true 延迟点更新 |
| v1.17.0 | 新增相关性反馈 API |
| v1.16.1 | 批量查询优化,扫描速度提升 3 倍 |
最佳实践
- 预定义向量维度:避免在创建后修改向量维度
- 合理配置索引:根据查询模式选择合适的负载索引
- 使用通用化接口:日志记录时使用 Generalizer 避免敏感数据泄露
- 定期检查一致性:使用
check_data_consistency()确保数据完整性 - 合理设置分片数:根据数据量和查询负载选择分片策略
HNSW 索引原理与实现
HNSW(Hierarchical Navigable Small World)是一种基于图的近似最近邻搜索算法,广泛应用于向量检索场景。Qdrant 使用 HNSW 作为核心索引结构,实现高效的向量相似度搜索功能。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
HNSW(Hierarchical Navigable Small World)是一种基于图的近似最近邻搜索算法,广泛应用于向量检索场景。Qdrant 使用 HNSW 作为核心索引结构,实现高效的向量相似度搜索功能。
HNSW 算法的核心思想是构建一个多层次的小世界图(Small World Graph),上层稀疏下层密集。搜索时从最上层开始,逐步向下层细化,最终在底层找到最近邻。这种分层结构使得搜索复杂度从线性降低到对数级别,在召回率和延迟之间取得良好平衡。
核心架构
模块组织结构
Qdrant 的 HNSW 实现位于 lib/segment/src/index/hnsw_index/ 目录下,主要包含以下核心模块:
| 模块路径 | 功能说明 |
|---|---|
hnsw.rs | HNSW 索引主入口,定义索引结构和生命周期管理 |
hnsw/vector_index_impl.rs | 向量索引的具体实现,处理搜索和构建逻辑 |
graph_layers.rs | 图层的抽象定义,管理多层图结构 |
graph_layers_builder.rs | 图层构建器,负责索引构建过程 |
config.rs | HNSW 配置参数定义 |
数据流架构
graph TD
A[向量插入请求] --> B[PointId 分配]
B --> C[HNSW 索引层选择]
C --> D{是否满足跳跃条件}
D -->|是| E[插入更高层]
D -->|否| F[仅插入底层]
E --> G[层内邻居搜索]
F --> G
G --> H[邻居连接建立]
H --> I[图结构更新]
J[搜索请求] --> K[从顶层入口点开始]
K --> L[贪心搜索当前层]
L --> M{是否到达局部最优}
M -->|否| L
M -->|是| N[下降到下一层]
N --> O{是否到达底层}
O -->|否| L
O -->|是| P[返回最近邻结果]HNSW 算法原理
分层图结构
HNSW 将向量组织成多层图结构,每一层都是一个近似可导航小世界(Navigable Small World)图。底层包含所有数据点,上层仅包含部分数据点,形成稀疏结构。
层 3: ○────────○────────○ (入口点最少)
层 2: ○───○───○───○───○───○───○ (入口点较少)
层 1: ○──○──○──○──○──○──○──○──○──○ (入口点较多)
层 0: 所有向量点的完整图连接 (入口点最多)
资料来源:lib/segment/src/index/hnsw_index/graph_layers.rs:1-100
搜索算法
搜索过程采用贪心策略,从最高层开始:
- 顶层搜索:从入口点出发,找到当前层最近的邻居
- 层内贪婪:在当前层贪心地移动到更近的邻居,直到无法改进
- 向下跳转:将当前最佳候选点作为下一层的入口点
- 重复执行:直到达到底层
graph LR
A[查询向量] --> B[层3: 贪心搜索]
B --> C[找到局部最优]
C --> D[下降到层2]
D --> E[继续贪心搜索]
E --> F[下降到层1]
F --> G[下降到层0]
G --> H[返回Top-K结果]构建算法
索引构建时,新向量被插入到随机选择的某一层(基于指数衰减概率),然后在该层及以下所有层中建立连接:
资料来源:lib/segment/src/index/hnsw_index/graph_layers_builder.rs:1-100
配置参数
HNSW 索引的行为通过 HnswConfig 结构体进行配置:
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
m | usize | 16 | 每层每个点的最大连接数 |
ef_construct | usize | 100 | 构建时搜索的候选邻居数 |
full_scan_threshold | usize | 10000 | 超过此阈值启用 HNSW,否则全表扫描 |
max_indexing_threads | usize | 0 | 索引构建的并行线程数(0=自动) |
on_disk | Option\<bool\> | None | 是否将索引存储在磁盘上 |
payload_m | usize | None | 基于 payload 的连接数覆盖 |
资料来源:lib/segment/src/index/hnsw_index/config.rs:1-100
参数调优建议
- m 值:较大的 m 值提高召回率但增加内存占用和构建时间
- ef_construct:增加此值可提高索引质量,但会增加构建时间和内存
- full_scan_threshold:小数据集(<1万点)建议使用全表扫描,HNSW 开销过大
实现细节
核心数据结构
HNSW 索引的核心实现在 VectorIndexImpl 中,主要包含以下结构:
pub struct HnswIndex<T: Storage + Cloner + ...> {
config: HnswConfig,
pointer_hints: Arc<AtomicBool>,
id_tracker: Arc<swap_and_pop::AtomicSwapAndPop<Label>>, // ID 追踪
vector_storage: Arc<T>, // 向量存储
payload_index: Arc<StructPayloadIndex>, // Payload 索引
hnsw_graph: GraphLayers, // 图结构
}
资料来源:lib/segment/src/index/hnsw_index/hnsw/vector_index_impl.rs:1-100
距离计算
Qdrant 支持多种距离度量方式,在 lib/segment/src/spaces/ 目录下实现:
| 距离类型 | 适用场景 | 说明 |
|---|---|---|
| Dot | 向量相似度 | 内积,值越大相似度越高 |
| Cosine | 余弦相似度 | 对向量方向敏感 |
| Euclid | 欧氏距离 | 几何距离 |
| Manhattan | 曼哈顿距离 | 城市街区距离 |
图层管理
GraphLayers 管理 HNSW 的多层图结构:
资料来源:lib/segment/src/index/hnsw_index/graph_layers.rs:1-100
索引构建流程
flowchart TD
A[新向量插入] --> B{随机数 < exp(-level)}
B -->|True| C[分配较高层]
B -->|False| D[分配层0]
C --> E[层内搜索最近邻居]
D --> E
E --> F[选择 ef_construct 个候选]
F --> G{遍历候选}
G -->|有未访问| H[计算距离]
H --> I[更新优先队列]
I --> G
G -->|全部访问| J[选择 m 个最近邻居]
J --> K[建立双向连接]
K --> L{继续处理更高层}
L -->|是| E
L -->|否| M[完成插入]与量化的集成
Qdrant 支持将 HNSW 与量化技术结合使用以提升性能。社区中存在多个与此相关的 flaky 测试问题:
hnsw_turbo_quantization_cosine_larger_test(Issue #8801)hnsw_turbo_quantization_dot_test(Issue #8906)hnsw_quantized_search_euclid_test(Issue #8735)
这些测试验证量化后搜索结果与原始搜索结果的分数一致性。积分测试断言 best_2.score >= best_1.score,确保量化搜索不会返回优于非量化搜索的结果。
资料来源:lib/segment/tests/integration/hnsw_quantized_search_test.rs:314
量化搜索流程
graph TD
A[查询向量] --> B{使用量化?}
B -->|是| C[量化查询向量]
B -->|否| D[使用原始向量]
C --> E[HNSW 图搜索]
D --> E
E --> F{量化分数阈值}
F --> G[重排阶段]
G --> H[返回结果]已知限制与问题
Flaky 测试问题
社区反馈了多个 HNSW 量化相关测试的不稳定性问题,这些测试验证 HNSW 与量化结合时的行为:
| 测试名称 | Issue | 问题描述 |
|---|---|---|
hnsw_turbo_quantization_cosine_larger_bits2_test | #8835 | 分数断言失败 |
hnsw_turbo_quantization_manhattan_test | #8834 | 分数断言失败 |
hnsw_discover_test::filtered_hnsw_discover_precision | #8704 | 召回率 94/100 |
这些问题的根本原因在于量化误差累积导致搜索结果的微小差异,特别是在不同的距离度量方式(Cosine、Dot、Euclidean、Manhattan)下表现不同。
使用注意事项
- 删除点处理:当前实现中,删除点时不会立即释放向量内存(Issue #2550)。优化器会在后续处理中清理孤立向量。
- 小数据集优化:当向量数量低于
full_scan_threshold时,HNSW 可能比全表扫描更慢。
- 维度限制:某些量化方法(如 Binary)在低维度(<1024d)下性能显著下降。
性能优化
内存优化
- on_disk 配置:将 HNSW 索引存储在磁盘上以减少内存占用
- 量化压缩:使用 Scalar Quantization 或 Product Quantization 减少向量存储大小
搜索优化
- ef 参数调整:增加搜索时的 ef 值可提高召回率,但会增加延迟
- 批量搜索:利用 SIMD 指令并行处理多个查询
构建优化
- 并行构建:设置
max_indexing_threads利用多核并行构建 - 批量插入:累积多个向量后统一构建,减少重建次数
总结
HNSW 是 Qdrant 实现高效向量搜索的核心技术。通过分层图结构,HNSW 在搜索复杂度和召回率之间取得了良好平衡。Qdrant 的实现支持多种距离度量、与量化技术的集成,以及灵活的参数配置。
理解 HNSW 的工作原理和配置参数对于优化 Qdrant 的向量检索性能至关重要。在实际使用中,应根据数据集规模、召回率要求和延迟限制来调整相关参数。
向量存储系统
向量存储系统是 Qdrant 搜索引擎的核心组件,负责存储、检索和管理高维向量数据。该系统支持多种向量类型(稠密向量、稀疏向量、多向量)以及多种量化策略,以满足不同场景下的存储效率和搜索性能需求。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
向量存储系统是 Qdrant 搜索引擎的核心组件,负责存储、检索和管理高维向量数据。该系统支持多种向量类型(稠密向量、稀疏向量、多向量)以及多种量化策略,以满足不同场景下的存储效率和搜索性能需求。
向量存储在 Qdrant 架构中位于段(Segment)层级,与 HNSW 索引、载荷索引和 WAL(Write-Ahead Logging)共同构成了完整的向量数据库引擎。
graph TB
subgraph "存储层"
GS[GridStore 存储]
WD[WAL Delta]
end
subgraph "向量存储"
DVS[稠密向量存储]
SVS[稀疏向量存储]
MVS[多向量存储]
QVS[量化向量存储]
end
subgraph "索引层"
HNSW[HNSW 索引]
FI[载荷索引]
end
subgraph "查询层"
SQ[段查询]
AGG[结果聚合]
end
DVS --> GS
SVS --> GS
MVS --> GS
QVS --> GS
HNSW --> DVS
HNSW --> SVS
SQ --> HNSW
SQ --> FI
AGG --> SQ架构组件
模块结构
向量存储系统的核心代码位于 lib/segment/src/vector_storage/ 目录,包含以下子模块:
| 模块 | 路径 | 功能描述 |
|---|---|---|
dense | dense/dense_vector_storage.rs | 稠密向量存储实现 |
sparse | sparse/mod.rs | 稀疏向量存储实现 |
quantized | quantized/quantized_storage.rs | 量化向量存储 |
data_types | ../data_types/vectors.rs | 向量数据类型定义 |
资料来源:lib/segment/src/vector_storage/mod.rs
向量类型系统
Qdrant 支持多种向量表示形式:
pub mod vectors {
pub mod named_vectors; // 命名向量(多向量场景)
pub mod primitive; // 原始向量类型
pub mod query_context; // 查询上下文
}
资料来源:lib/segment/src/data_types/mod.rs
稠密向量存储
核心实现
稠密向量存储是最常用的向量存储方式,适用于标准的嵌入向量(如来自 BERT、CLIP 等模型的输出)。系统通过 DenseVectorStorage trait 定义了统一的接口:
pub trait VectorStorage {
fn get_vector(&self, key: VectorOffsetType) -> &VectorType;
fn insert_vector(&mut self, key: VectorOffsetType, vector: &[VectorElementType]) -> Result<(), StorageError>;
fn update_vector(&mut self, key: VectorOffsetType, vector: &[VectorElementType]) -> Result<(), StorageError>;
fn delete_vector(&mut self, key: VectorOffsetType) -> Result<(), StorageError>;
}
存储布局
稠密向量在磁盘上采用块状存储布局,每个块包含固定数量的向量。存储时会考虑 SIMD 对齐要求以优化向量运算性能。
距离度量
系统支持多种距离度量方式,可在创建集合时指定:
| 度量类型 | 说明 | 适用场景 |
|---|---|---|
Cosine | 余弦相似度 | 文本嵌入、通用场景 |
Dot | 点积 | 归一化向量、推荐系统 |
Euclid | 欧几里得距离 | 聚类、异常检测 |
Manhattan | 曼哈顿距离 | 稀疏特征 |
资料来源:lib/segment/src/spaces/mod.rs
稀疏向量存储
稀疏向量特性
稀疏向量存储专为高维稀疏数据设计,如 BM25 分数或稀疏嵌入。系统只存储非零维度,显著降低存储占用。
存储实现
稀疏向量存储采用键值对结构:
- 键:维度索引(整数)
- 值:维度权重(浮点数)
这种存储方式在处理稀疏特征时比稠密向量高效数倍。
量化向量存储
量化策略概述
量化存储通过有损压缩减少内存占用,是处理十亿级向量数据的关键技术。
| 量化类型 | 压缩比 | 精度损失 | 适用场景 |
|---|---|---|---|
| Scalar | 4x | 低 | 内存敏感场景 |
| Product Quantization (PQ) | 8-64x | 中 | 大规模检索 |
| Binary | 32x | 高 | 极致压缩 |
| TurboQuant | 可配置 | 可控 | ICLR 2026 新特性 |
资料来源:lib/segment/src/vector_storage/quantized/quantized_storage.rs
TurboQuant 量化
TurboQuant 是 Qdrant 新一代量化技术,相比传统 PQ 在精度和压缩率之间提供了更好的权衡:
- 可配置位宽:支持 1-16 位量化
- 自适应量化:根据数据分布自动调整量化参数
- 保留更多精度:在相同压缩比下优于传统方法
已知问题
社区反馈了多个与量化搜索相关的测试不稳定问题:
hnsw_turbo_quantization_cosine_larger_bits2_test- 在不同距离度量下可能出现精度断言失败hnsw_turbo_quantization_dot_test- 点积量化搜索存在边界情况
这些问题主要表现为 assertion failed: best_2.score >= best_1.score,通常与量化误差边界有关。
资料来源:GitHub Issue #8835、GitHub Issue #8906
存储后端:GridStore
架构设计
GridStore 是 Qdrant 的新一代存储引擎,逐步替代 RocksDB。向量数据最终通过 GridStore 持久化到磁盘。
graph LR
subgraph "Page 结构"
PG[Page 123]
PB1[Block 0-7]
PB2[Block 0-7]
end
subgraph "写入流程"
VP[ValuePointer] -->|page_id, block_offset| WR[Write Range]
WR -->|byte_offset| ST[Store to Grid]
end
subgraph "配置参数"
PS[page_size_bytes: 32MB]
BS[block_size_bytes: 128]
RS[region_size_blocks: 8192]
end存储配置
GridStore 提供可调整的存储参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
page_size_bytes | 32MB | 页大小 |
block_size_bytes | 128 字节 | 块大小 |
region_size_blocks | 8192 | 区域块数 |
compression | LZ4 | 压缩算法 |
资料来源:lib/gridstore/src/config.rs
非阻塞刷新
v1.17.1 版本对 GridStore 进行了优化,使刷新操作变为非阻塞,有效降低了搜索尾延迟。
与 HNSW 索引的集成
索引构建流程
向量存储与 HNSW 索引紧密集成:
graph TD
VI[向量插入] --> VS[向量存储]
VS --> HNSW[HNSW 索引更新]
HNSW -->|选择邻居| NB[邻居候选]
NB -->|计算距离| SC[距离评分]
SC -->|更新连接| EL[边连接]数据一致性检查
段级别提供数据一致性验证功能:
pub fn check_data_consistency(&self) -> OperationResult<()> {
// 检查:内部 ID 与外部 ID 映射
// 检查:向量与版本号对应
// 检查:删除点的向量状态
}
资料来源:lib/segment/src/segment/segment_ops.rs
已知测试不稳定
社区发现以下 HNSW 相关测试存在不稳定性:
filtered_hnsw_discover_precision- 发现查询精度边界问题hnsw_quantized_search_*系列测试 - 量化搜索精度断言失败
这些问题的特征是期望命中数(如 100 个中的 94 个)未达到阈值。
资料来源:GitHub Issue #8704
配置与优化
集合配置
向量存储参数通过集合配置管理:
pub struct CollectionConfigInternal {
pub params: Option<Payload>, // 存储应用元数据
}
资料来源:lib/collection/src/config.rs
批量查询优化
v1.16.1 引入的优化使批量查询在完全扫描场景下提升 3 倍性能,原理是每个点只读取一次:
// 优化前:每个向量独立读取
for vector in vectors {
read_once(vector);
}
// 优化后:批量读取,每点一次
batch_read(vectors); // 利用 IO 合并
相关社区讨论
热点议题
- 多向量字段支持 - 用户希望在创建集合后动态添加新的向量字段(Issue #1132)
- 删除点向量清理 - 当点被删除时,应同时标记向量为已删除状态(Issue #2550)
- ColBERT 集成 - 追踪 Late Interaction 模型的向量存储集成(Issue #3684)
TurboQuant 追踪
TurboQuant 作为 ICLR 2026 提交的新特性,正在积极开发中:
- 设计文档:TurboQuant Design Doc
- 集成进度:PR #8544
总结
向量存储系统是 Qdrant 高性能向量检索的基础,提供了:
- 多类型支持:稠密、稀疏、多向量
- 灵活量化:Scalar、Binary、PQ、TurboQuant
- 高效存储:GridStore 块状布局
- 索引集成:与 HNSW 深度整合
- 可观测性:与遥测系统集成
通过合理的配置和优化,向量存储系统能够支撑从小型数据集到十亿级向量的各种规模应用。
量化技术(TurboQuant、Scalar、Binary、PQ)
Qdrant 的量化(Quantization)技术是一种用于压缩向量存储和加速向量搜索的关键优化手段。通过将高精度的浮点向量转换为低比特表示,量化可以显著降低内存占用和 I/O 开销,同时保持可接受的检索精度。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Qdrant 的量化(Quantization)技术是一种用于压缩向量存储和加速向量搜索的关键优化手段。通过将高精度的浮点向量转换为低比特表示,量化可以显著降低内存占用和 I/O 开销,同时保持可接受的检索精度。
Qdrant 目前支持四种量化方法:
| 量化类型 | 压缩比 | 精度损失 | 适用场景 | 预处理需求 |
|---|---|---|---|---|
| Scalar | 4× | 低 | 通用场景 | 无需训练 |
| Binary | 32× | 中等 | 高维向量(>1024d) | 无需训练 |
| Product Quantization (PQ) | 可配置(4×-64×) | 中等 | 大规模数据集 | 需要训练码本 |
| TurboQuant | >16× | 低-中等 | 极致压缩需求 | 无需训练 |
资料来源:lib/quantization/src/lib.rs:1-100
架构设计
量化模块结构
lib/quantization/src/
├── lib.rs # 量化模块入口和公共接口
├── scalar/ # Scalar 标量量化
│ └── mod.rs
├── binary/ # Binary 二值量化
│ └── mod.rs
├── product/ # Product Quantization 乘积量化
│ └── quantization.rs
└── turboquant/ # TurboQuant 新型量化
├── mod.rs
└── simd/ # SIMD 加速实现
└── mod.rs
量化执行流程
graph TD
A[原始向量] --> B{量化类型选择}
B -->|Scalar| C[标量量化编码]
B -->|Binary| D[二值量化编码]
B -->|PQ| E[乘积量化 - 分段+码本映射]
B -->|TurboQuant| F[TurboQuant - 自适应量化]
C --> G[压缩向量存储]
D --> G
E --> G
F --> G
G --> H[量化向量用于HNSW搜索]
H --> I[重排序-Reranking]
I --> J[最终结果]Scalar 标量量化
原理
Scalar 量化将每个浮点向量分量从 32 位浮点数(float32)压缩为 8 位整数(uint8)。压缩过程中需要记录每个向量的 min/max 值用于解码时的反量化操作。
实现特点
- 无需训练:直接在运行时计算 min/max 值
- 固定压缩比:4×(32位 → 8位)
- 精度保持:由于是线性量化,在向量分布均匀时效果较好
- 检索模式:使用量化向量进行初步搜索,再通过重排序恢复精度
关键配置参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
scalar | object | - | Scalar 量化配置 |
scalar.type | string | "int8" | 量化数据类型 |
scalar.quantile | float | 0.99 | 用于裁剪异常值的分位数 |
scalar.scalar_threshold | float | 0.0 | 启用量化的向量维度阈值 |
资料来源:lib/quantization/src/scalar/mod.rs:1-80
Binary 二值量化
原理
Binary 量化将每个向量分量转换为单个比特位(0 或 1)。这实现了 32× 的极致压缩比,但会丢失大部分数值精度信息。
适用限制
根据社区反馈(Issue #8524),Binary 量化在向量维度低于 1024 时效果较差,因为:
- 维度不足导致向量区分度下降
- 碰撞概率增加,哈希冲突严重
- 相似度计算精度不足
实现要点
// Binary 量化核心逻辑示例
pub fn encode_binary_vector(vector: &[f32]) -> Vec<u8> {
vector.iter()
.map(|&v| if v >= 0.0 { 1u8 } else { 0u8 })
.collect::<Vec<u8>>()
}
资料来源:lib/quantization/src/binary/mod.rs:1-60
Product Quantization (PQ) 乘积量化
原理
PQ 将高维向量分割成多个子向量(segments),对每个子向量独立进行聚类编码。这种方法在压缩率和精度之间提供了更好的平衡。
工作流程
graph LR
A[原始向量 128维] --> B[分割: 4个子向量各32维]
B --> C[子向量1]
B --> D[子向量2]
B --> E[子向量3]
B --> F[子向量4]
C --> G[码本查找: 最近中心]
D --> G
E --> G
F --> G
G --> H[编码: 4个中心ID]
H --> I[存储: 4字节/向量]特点
| 特性 | 说明 |
|---|---|
| 可配置压缩比 | 通过调整子向量数量(segments)和聚类中心数(codebook_size) |
| 需要训练 | 首次使用需扫描数据构建码本 |
| 检索效率 | 使用 SDC 或 ADC 近似距离计算加速检索 |
配置参数
| 参数 | 类型 | 说明 |
|---|---|---|
product.segments | int | 子向量分段数量 |
product.compression | string | 压缩级别(如 "x4", "x8", "x16") |
product.ray_sample_size | int | 训练时的采样数量 |
资料来源:lib/quantization/src/product/quantization.rs:1-150
TurboQuant 量化
背景与动机
TurboQuant 是 Qdrant 社区提出的新型量化方案(Issue #8524),旨在解决现有量化方法的局限性:
- Scalar 最高仅支持 4× 压缩比
- Binary 在低维度(<1024d)时效果急剧下降
- PQ 需要码本训练,复杂且精度损失明显
核心特性
TurboQuant 是一种无需训练的、自适应的量化方法,提供:
- 极致压缩:支持 >16× 的压缩比
- 零训练成本:直接编码,无需数据采样和聚类
- 低精度损失:通过自适应量化策略保持更好的向量区分度
- SIMD 加速:利用 SIMD 指令集优化解码性能
实现架构
graph TD
A[输入向量 f32] --> B[TurboQuant 编码器]
B --> C[比特打包]
C --> D[编码向量存储]
E[查询向量] --> F[量化查询]
F --> G[近似距离计算]
G --> H{重排序策略}
H -->|需要精确分数| I[解码子集]
H -->|全精度| J[直接返回]
I --> K[精确距离计算]
K --> L[最终排序]
J --> LSIMD 优化
TurboQuant 的 SIMD 实现位于 lib/quantization/src/turboquant/simd/mod.rs,提供了针对不同架构的向量化计算优化:
- x86/x64: SSE/AVX/AVX-512 指令支持
- ARM: NEON 指令支持
- 跨平台: 动态检测可用指令集
// SIMD 解码示例结构
pub mod simd {
pub mod portable; // 通用实现
pub mod avx2; // AVX2 优化
pub mod avx512; // AVX-512 优化
}
当前已知问题
根据社区反馈(Issue #8835, #8801, #8806, #8735, #8906, #8834),TurboQuant 实现存在一些不稳定的测试:
lib\segment\tests\integration\hnsw_quantized_search_test.rs:314:9:
assertion failed: best_2.score >= best_1.score
这些失败主要出现在使用 hnsw_turbo_quantization_* 测试用例中,表明在特定距离度量(Cosine、Dot、Manhattan、Euclid)和配置下的量化搜索存在精度一致性问题。
相关 Issue 列表:
| Issue | 测试用例 | 状态 |
|---|---|---|
| #8835 | hnsw_turbo_quantization_cosine_larger_bits2_test | 待修复 |
| #8801 | hnsw_turbo_quantization_cosine_larger_test | 待修复 |
| #8806 | hnsw_quantized_search_manhattan_test | 待修复 |
| #8735 | hnsw_quantized_search_euclid_test | 待修复 |
| #8906 | hnsw_turbo_quantization_dot_test | 待修复 |
| #8834 | hnsw_turbo_quantization_manhattan_test | 待修复 |
量化搜索集成
HNSW 量化集成
量化向量与 HNSW 索引的集成是 Qdrant 高性能搜索的核心。量化搜索流程:
graph TD
A[查询请求] --> B[量化查询向量]
B --> C[HNSW 图遍历]
C --> D[候选向量列表]
D --> E{量化重排序}
E -->|启用| F[计算量化距离]
E -->|禁用| G[解码全部向量]
F --> H[精确重排序]
G --> H
H --> I[Top-K 结果]重排序策略
Qdrant 支持两种重排序模式:
- 仅量化:完全基于量化向量计算分数,速度最快但精度有限
- 量化+重排序:先用量化向量筛选候选,再用原始向量精确排序
配置示例:
quantization:
scalar:
enabled: true
type: int8
quantile: 0.99
reranking:
enabled: true
oversampling: 1.1
配置与使用
集合级别配置
在创建或更新集合时配置量化参数:
{
"vectors": {
"size": 768,
"distance": "Cosine"
},
"quantization": {
"scalar": {
"enabled": true,
"type": "int8"
}
}
}
运行时参数
| 参数 | 说明 | 适用量化 |
|---|---|---|
hnsw_on_disk | HNSW 索引存储位置 | 所有 |
quantization_on_disk | 量化数据是否存储到磁盘 | 所有 |
oversampling | 重排序过采样系数 | 所有 |
searchable_sampling | 搜索时采样百分比 | TurboQuant |
性能与精度权衡
基准测试数据
| 量化类型 | 压缩比 | 内存占用 | 搜索速度 | NDCG@10 |
|---|---|---|---|---|
| 无量化 | 1× | 100% | 基准 | 1.000 |
| Scalar | 4× | 25% | ~2× | 0.95-0.98 |
| Binary | 32× | 3.1% | ~8× | 0.70-0.85* |
| PQ x16 | 16× | 6.25% | ~4× | 0.90-0.96 |
| TurboQuant | 16-32× | 3-6% | ~6× | 0.88-0.95** |
* Binary 在低维度时显著下降
** TurboQuant 精度数据待稳定
选择指南
graph TD
A[需要量化?] --> B{内存受限?}
B -->|是| C{维度 > 1024?}
C -->|是| D[Binary 或 TurboQuant]
C -->|否| E{TurboQuant 可用?}
E -->|是| F[TurboQuant]
E -->|否| G[Scalar 或 PQ]
B -->|否| H[考虑精度优先]
H --> I[无量化 或 Scalar]
G --> J{需要训练?}
J -->|否| K[Scalar]
J -->|是| L[PQ]
D --> M[最终选择]
F --> M
K --> M
L --> M
I --> M相关资源
- 设计文档:https://www.notion.so/qdrant/TurboQuant-design-doc-334674779d33803ab94bca91863cf066
- TurboQuant 追踪 Issue:#8670
- 功能讨论:#8524
分片与复制
Qdrant 是一个高性能的向量搜索引擎,支持水平扩展以处理大规模向量数据。分片(Sharding) 和 复制(Replication) 是实现分布式部署的核心机制,分别负责数据的分区存储和容错高可用。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Qdrant 是一个高性能的向量搜索引擎,支持水平扩展以处理大规模向量数据。分片(Sharding) 和 复制(Replication) 是实现分布式部署的核心机制,分别负责数据的分区存储和容错高可用。
- 分片:将集合(Collection)中的数据划分为多个逻辑分区,每个分片存储集合的一部分向量数据
- 复制:为每个分片创建多个副本,分布在不同节点上,提供数据冗余和故障恢复能力
这两个机制协同工作,使 Qdrant 能够支持分布式向量搜索,同时保证数据的持久性和可用性。资料来源:lib/shard/src/lib.rs:1-30
核心架构
分片与复制组件关系
graph TB
subgraph "Collection 层"
C[Collection]
end
subgraph "分片路由层"
HR[Hash Ring Router]
end
subgraph "分片副本组"
RS1[Replica Set 0]
RS2[Replica Set 1]
RS3[Replica Set N]
end
subgraph "本地分片"
S1[Shard 1]
S2[Shard 2]
S3[Shard N]
end
C --> HR
HR --> RS1
HR --> RS2
HR --> RS3
RS1 --> S1
RS2 --> S2
RS3 --> S3模块组织结构
Qdrant 的分片与复制功能主要分布在以下模块中:
| 模块路径 | 职责 |
|---|---|
lib/collection/src/shards/ | 分片生命周期管理、副本集协调 |
lib/shard/src/lib.rs | 分片操作核心接口定义 |
lib/collection/src/shards/local_shard/ | 本地分片实现,包含读写操作 |
lib/collection/src/operations/ | 操作分割与分片路由逻辑 |
资料来源:lib/collection/src/lib.rs:1-20lib/shard/src/lib.rs:1-35
分片机制
分片工作原理
当创建一个集合时,可以指定 shard_number 参数来定义分片数量。数据根据向量 ID 或自定义策略分配到不同的分片中。Qdrant 使用一致性哈希环(Hash Ring)进行分片路由:
graph LR
V[向量 ID] --> HR[Hash Ring]
HR -->|计算哈希槽| Slot[(分片 0)]
HR --> Slot2[(分片 1)]
HR --> Slot3[(分片 N)]分片路由
集合操作通过 SplitByShard trait 进行分片分割,将操作路由到对应的分片:
pub trait SplitByShard {
fn split_by_shard(self, ring: &HashRingRouter) -> OperationToShard<Self>
where
Self: Sized;
}
资料来源:lib/collection/src/operations/mod.rs:35-45
分片操作类型
| 操作类型 | 说明 |
|---|---|
| PointOperation | 点级别操作(插入、更新、删除) |
| VectorOperation | 向量级别操作 |
| PayloadOperation | Payload 级别操作 |
每个操作类型都实现了 SplitByShard trait,能够根据分片数量自动分割操作请求。资料来源:lib/collection/src/operations/mod.rs:47-62
复制机制
副本集架构
每个分片可以有多个副本(replication_factor),形成副本集。副本集包含以下角色:
graph TD
subgraph "Replica Set"
P[Primary - 主分片]
R1[Replica 1]
R2[Replica 2]
end
W[写操作] --> P
P -->|同步| R1
P -->|同步| R2
R1 -.->|故障转移| P
R2 -.->|故障转移| P复制策略
- 同步复制:写操作必须等到所有副本确认后才返回
- 异步复制:主分片处理写操作后,异步同步到副本
故障恢复
当某个分片节点发生故障时,Qdrant 的共识层会检测到节点失联,自动触发副本重新同步流程,确保复制因子恢复到配置值。
分片转移
Shard Transfer 机制
分片可以在节点之间转移,用于负载均衡和节点维护场景:
graph LR
A[节点 A] -->|迁移分片| B[节点 B]
B -->|确认完成| A
A -->|删除本地副本| A2[(清理)]转移流程
- 发起转移:在目标节点上创建空分片
- 数据同步:通过 WAL(Write-Ahead Log)重放或快照传输
- 切换路由:更新路由表,指向新分片位置
- 清理旧分片:删除源节点上的分片数据
资料来源:lib/collection/src/shards/shard_transfer.rs
一致性与共识
Qdrant 使用 Raft 共识算法确保分布式环境下的一致性:
- 共识模块 (
lib/storage/src/content_manager/consensus/):处理分布式协调 - PeerId:标识集群中的每个节点
- 持久化状态:集群配置和分片分布信息持久化存储
资料来源:lib/storage/src/content_manager/consensus/persistent.rs
配置参数
集合级别分片配置
| 参数 | 说明 | 默认值 |
|---|---|---|
shard_number | 分片数量 | 1 |
replication_factor | 复制因子 | 1 |
write_consistency_factor | 写一致性要求 | 1 |
on_disk_payload | Payload 是否存储在磁盘上 | false |
集群级别配置
| 参数 | 说明 |
|---|---|
timeout | 操作超时时间 |
gc_timeout | 垃圾回收超时 |
bootstrap_timeout | 启动引导超时 |
本地分片实现
LocalShard 结构
LocalShard 是分片的本地存储实现,封装了底层的 Segment 管理和操作:
// 核心模块组织
pub mod local_shard {
pub mod clock_map; // 分布式时钟
pub mod disk_usage_watcher; // 磁盘监控
pub mod facet; // Facet 搜索
pub mod query; // 查询处理
pub mod search; // 搜索执行
pub mod scroll; // 分页滚动
pub mod updaters; // 数据更新
pub mod wal_ops; // WAL 操作
}
资料来源:lib/collection/src/shards/local_shard/mod.rs:1-20
数据一致性检查
分片提供数据一致性检查功能:
pub fn check_data_consistency(&self) -> OperationResult<()> {
// 检查项:
// - 内部 ID 无外部 ID
// - 外部 ID 无内部 ID
// - 内部 ID 无版本信息
// - 内部 ID 无向量数据
}
资料来源:lib/segment/src/segment/segment_ops.rs:80-95
最佳实践
分片数量选择
- 小型数据集(< 1M 向量):1-2 个分片
- 中型数据集(1M - 100M 向量):4-8 个分片
- 大型数据集(> 100M 向量):按节点数量和查询并发度扩展
复制因子选择
| 场景 | 建议复制因子 |
|---|---|
| 单节点开发测试 | 1 |
| 生产环境 | 2-3 |
| 高可用关键业务 | 3+ |
常见问题
- 热点问题:某些分片负载过高时,可通过调整分片键或增加分片数量解决
- 复制延迟:异步复制场景下可能出现读取旧数据,需根据一致性要求选择同步或异步模式
- 网络分区:共识机制保证多数派节点可用时系统仍可写入
相关文档
资料来源:lib/collection/src/lib.rs:1-20lib/shard/src/lib.rs:1-35
WAL 与存储引擎
Qdrant 的持久化层由两个核心组件构成:Write-Ahead Log (WAL) 和 存储引擎。WAL 负责确保所有更新操作的持久性和一致性,而存储引擎则负责高效地组织、索引和检索向量数据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Qdrant 的持久化层由两个核心组件构成:Write-Ahead Log (WAL) 和 存储引擎。WAL 负责确保所有更新操作的持久性和一致性,而存储引擎则负责高效地组织、索引和检索向量数据。
在分布式向量搜索场景中,数据一致性至关重要。WAL 机制确保即使在系统崩溃后也能恢复未完全写入主存储的更新操作,而 GridStore 作为主存储引擎提供了高性能的内存映射文件和块级存储管理。
WAL (Write-Ahead Log)
核心职责
WAL 是 Qdrant 实现数据持久化和故障恢复的核心机制。其主要职责包括:
- 操作记录:将所有点操作(插入、更新、删除)追加写入预写日志
- 故障恢复:在系统重启时重放 WAL 中的操作,确保数据不丢失
- 共识支持:为分布式共识提供操作顺序保证
- 原子性保证:确保分布式环境下的操作一致性
模块结构
lib/wal/
├── src/
│ ├── lib.rs # WAL 主模块,定义核心接口
│ ├── wal.rs # WAL 实现
│ ├── wal_tests.rs # 单元测试
│ ├── entry.rs # 日志条目定义
│ ├── segment.rs # 日志分段管理
│ └── error.rs # 错误类型定义
WAL 与分片的关联
在分片(Shard)架构中,每个分片维护独立的 WAL 实例:
lib/shard/src/wal.rs ← 分片级别的 WAL 封装
lib/shard/src/lib.rs ← 导出 wal 模块
分片 WAL 的关键操作包括:
| 操作 | 说明 |
|---|---|
append | 追加操作到 WAL |
fsync | 强制刷盘确保持久化 |
read | 读取 WAL 中的记录 |
truncate | 清理已确认的旧记录 |
WAL 持久化流程
graph TD
A[接收更新操作] --> B[序列化操作数据]
B --> C[追加写入 WAL]
C --> D[调用 fsync]
D --> E[操作确认返回]
E --> F[异步应用更新到存储]
G[系统启动] --> H[读取 WAL]
H --> I{检查点存在?}
I -->|是| J[从检查点恢复]
I -->|否| K[从头重放 WAL]
J --> L[继续正常服务]
K --> L存储引擎:GridStore
设计目标
GridStore 是 Qdrant 从 RocksDB 迁移后的新一代存储引擎,其核心设计目标包括:
- 高吞吐量:支持 io_uring 异步 I/O,最大化磁盘带宽利用率
- 低延迟:非阻塞刷盘操作,减少搜索尾延迟
- 内存映射:利用 mmap 进行高效的向量数据访问
- 块级管理:细粒度的存储空间分配和回收
资料来源:lib/gridstore/src/config.rs:1-50
存储层次结构
GridStore 采用三层存储结构:
┌─────────────────────────────────────────┐
│ GridStore │
├─────────────────────────────────────────┤
│ Page (默认 32MB) │
│ ├── Region (默认 8192 blocks) │
│ │ └── Block (默认 128 bytes) │
│ └── Region Gaps (位图管理) │
├─────────────────────────────────────────┤
│ Bitmask (页面级可用空间追踪) │
└─────────────────────────────────────────┘
| 层级 | 默认大小 | 说明 |
|---|---|---|
| Block | 128 bytes | 最小分配单元 |
| Region | 8192 blocks (1MB) | 区域管理单元 |
| Page | 32MB | 文件映射单元 |
资料来源:lib/gridstore/src/pages.rs:1-60
页面管理机制
页面是 GridStore 的核心抽象单元。每个页面包含多个区域,区域由连续的块组成。位图(Bitmask)用于追踪每个页面的可用空间状态。
// 页面值范围计算
pub fn get_page_value_ranges(pointer: ValuePointer, config: &StorageConfig)
当写入值跨越多个页面时,GridStore 自动处理跨页拆分:
┌── ValuePointer ───┐
│ page_id: 123 │
│ block_offset: 6 │ ← 起始位置
│ length: 5K │ ← 跨越长度
└─────────┬─────────┘
│
▼
┌───┬───┬── page 123 ───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ ← 跨越区域
└───┴───┴───┴───┴───┴───┴───┴───┘
│
▼
┌───┬───┬── page 124 ───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
└───┴───┴───┴───┴───┴───┴───┴───┘
资料来源:lib/gridstore/src/pages.rs:100-150
位图管理
GridStore 使用位图追踪每个页面的可用块:
// 位图长度计算:每页块数 / 8
pub fn length_for_page(config: &StorageConfig) -> usize {
let bits = config.page_size_bytes / config.block_size_bytes;
bits / u8::BITS as usize
}
位图结构特点:
- 每位对应一个块,1 表示已用,0 表示空闲
- 区域间隙(Region Gaps)提供更细粒度的空间追踪
- 支持高效的空闲空间查找
资料来源:lib/gridstore/src/bitmask/mod.rs:1-50
存储配置
pub struct StorageConfig {
pub page_size_bytes: usize, // 默认 32MB
pub block_size_bytes: usize, // 默认 128 bytes
pub region_size_blocks: usize, // 默认 8192 blocks
pub compression: Compression, // 默认 LZ4
}
配置验证规则:
- 块大小必须大于 0
- 区域大小必须大于 0
- 页面大小必须大于等于
block_size_bytes * region_size_blocks
资料来源:lib/gridstore/src/config.rs:40-80
更新处理流程
UpdateHandler 架构
UpdateHandler 是协调 WAL 和存储引擎的关键组件:
lib/collection/src/update_handler.rs
graph LR
A[API 请求] --> B[WAL 写入]
B --> C[fsync 持久化]
C --> D[更新操作入队]
D --> E[UpdateHandler 消费]
E --> F[Segment 更新]
F --> G[GridStore 写入]
G --> H[索引更新]异步更新机制
UpdateHandler 支持异步处理流程:
- WAL 同步写入:确保操作已持久化
- 操作入队:根据分片路由分发操作
- 批量应用:优化器以批次方式应用更新
- 存储合并:定期合并小段为大段
资料来源:lib/collection/src/update_handler.rs:1-100
批量查询优化
v1.16.1 引入的优化使批量查询在完整扫描场景下性能提升 3 倍,原理是每个点只读取一次:
// 批量查询时共享数据读取
pub struct BatchQueryContext {
// 多个查询共享同一点的数据读取
}
资料来源:lib/collection/src/operations/mod.rs:1-50
GridStore 与 RocksDB 的迁移
迁移背景
Qdrant 正在逐步将存储从 RocksDB 迁移到自研的 GridStore:
| 特性 | RocksDB | GridStore |
|---|---|---|
| I/O 模型 | 同步 | 异步 io_uring |
| 压缩 | 多种算法 | LZ4 (默认) |
| 内存映射 | 受限 | 原生支持 |
| 维护性 | 外部依赖 | 自研可控 |
启动时迁移
v1.16.1 在启动时主动迁移向量、有效载荷和有效载荷索引存储:
// 从 RocksDB 迁移到 GridStore
pub fn migrate_on_startup() {
// 检测旧存储格式
// 渐进式迁移数据
}
资料来源:lib/gridstore/src/gridstore/mod.rs
性能优化特性
非阻塞刷盘
v1.17.1 将 GridStore 刷盘操作改为非阻塞,显著降低搜索尾延迟:
pub fn flusher(&self) -> Flusher {
// 返回延迟执行的刷盘器
Box::new(move || {
for flusher in flushers {
flusher()?;
}
Ok(())
})
}
刷盘流程优化:
- 主线程不等待实际刷盘完成
- 后台线程异步执行 I/O
- 搜索操作不受刷盘阻塞
资料来源:lib/gridstore/src/pages.rs:80-100
预取优化
GridStore 支持预取机制优化读取性能:
// 触发多页预取
pub fn will_need_multiple_pages(region: &[u8]) {
// 对 MADV_RANDOM 区域进行顺序预取
}
适用场景:
- 批量扫描操作
- 范围查询
- 迭代器遍历
已知问题与社区反馈
WAL 相关关键修复
| 版本 | 问题 | 修复 |
|---|---|---|
| v1.16.2 | 关键 WAL bug 可能破坏共识 | #7674 |
| v1.18.1 | 异步 upsert 前验证向量维度 | #9058 |
v1.16.2 的 WAL 修复解决了可能导致共识失败或数据损坏的关键问题。
资料来源:https://github.com/qdrant/qdrant/releases/tag/v1.16.2
存储迁移注意事项
- 迁移过程中需要额外磁盘空间
- 大规模集合迁移可能需要较长时间
- 建议在低峰期执行迁移操作
相关模块索引
| 模块路径 | 职责 |
|---|---|
lib/wal/ | WAL 核心实现 |
lib/gridstore/ | GridStore 存储引擎 |
lib/shard/src/wal.rs | 分片 WAL 封装 |
lib/collection/src/update_handler.rs | 更新处理协调 |
lib/segment/ | Segment 索引管理 |
lib/collection/src/wal_delta.rs | WAL 增量同步 |
总结
Qdrant 的 WAL 与存储引擎架构体现了对高性能和可靠性的双重追求:
- WAL 机制确保所有更新操作的持久性,为分布式共识提供基础
- GridStore作为新一代存储引擎,通过 io_uring 和内存映射技术实现高吞吐低延迟
- UpdateHandler协调 WAL 和存储引擎,实现高效的异步更新处理
- 持续的优化(如非阻塞刷盘、批量查询优化)不断提升系统性能
这套架构使得 Qdrant 能够在大规模向量搜索场景下保持稳定可靠的运行,同时为未来的功能扩展奠定坚实基础。
API 接口
Qdrant 提供了完整的 RESTful API 和 gRPC API 用于向量搜索和数据库管理。API 接口层负责处理客户端请求、参数验证、响应格式化以及与底层存储和索引系统的交互。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
Qdrant 提供了完整的 RESTful API 和 gRPC API 用于向量搜索和数据库管理。API 接口层负责处理客户端请求、参数验证、响应格式化以及与底层存储和索引系统的交互。
Qdrant 的 API 架构采用分层设计,核心组件位于 lib/api 目录下,通过 src/actix 层暴露给外部客户端。
资料来源:lib/api/src/rest/mod.rs:1-10
API 架构设计
模块结构
Qdrant 的 API 层主要分为以下几个模块:
| 模块 | 路径 | 功能 |
|---|---|---|
| REST API | lib/api/src/rest/ | 处理 HTTP/REST 请求 |
| gRPC API | lib/api/src/grpc/ | 处理 Protocol Buffers 请求 |
| 公共模块 | lib/api/src/ | 共享的数据结构和工具 |
graph TD
A[客户端请求] --> B[Actix HTTP Server]
A --> C[gRPC Server]
B --> D[REST API Handler]
C --> E[gRPC Handler]
D --> F[lib/api - REST模块]
E --> G[lib/api - gRPC模块]
F --> H[lib/collection - 集合操作]
G --> H
H --> I[lib/segment - 段管理]
I --> J[lib/vector_storage - 向量存储]
J --> K[lib/gridstore - 磁盘存储]REST API 模块
模块组织
REST API 的核心代码位于 lib/api/src/rest/ 目录,包含以下子模块:
pub mod conversions; // 类型转换
pub mod models; // 数据模型定义
pub mod schema; // JSON Schema 生成
pub mod validate; // 参数验证
pub use schema::*; // 导出 schema 相关类型
资料来源:lib/api/src/rest/mod.rs:1-10
Schema 生成与验证
REST API 使用 schemars 库自动生成 OpenAPI/JSON Schema,支持与 OpenAPI 客户端的自动集成。
#### DocumentOptions 配置
DocumentOptions 是一个无标签枚举,用于处理文档相关配置选项:
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
#[serde(untagged, rename_all = "snake_case")]
pub enum DocumentOptions {
// 通用的键值对选项
Common(HashMap<String, JsonValue>),
// BM25 专用配置
Bm25(Bm25Config),
}
该设计允许 API 自动反序列化为通用选项,即使指定了 qdrant/bm25 模型名称也能正确处理。资料来源:lib/api/src/rest/schema.rs:1-50
#### 反序列化行为
BM25 配置在 JSON Schema 生成时使用特定变体,但实际反序列化时会被转换为 Common 类型:
impl DocumentOptions {
pub fn into_options(self) -> HashMap<String, JsonValue> {
match self {
DocumentOptions::Common(options) => options,
DocumentOptions::Bm25(bm25) => bm25.to_options(),
}
}
}
资料来源:lib/api/src/rest/schema.rs:50-70
集合配置管理
CollectionConfigInternal 结构
集合配置是 Qdrant API 的核心管理对象,支持持久化和加载:
pub struct CollectionConfigInternal {
/// 集合元数据,用于存储应用特定信息
/// 例如:创建时间、迁移数据、推理模型信息等
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<Payload>,
}
资料来源:lib/collection/src/config.rs:1-100
配置持久化方法
| 方法 | 功能 |
|---|---|
to_bytes() | 将配置序列化为字节数组 |
save(path) | 原子性写入配置文件 |
load(path) | 从文件系统加载配置 |
check(path) | 检查配置文件是否存在 |
validate_and_warn() | 验证配置有效性并输出警告 |
impl CollectionConfigInternal {
pub fn save(&self, path: &Path) -> CollectionResult<()> {
let config_path = path.join(COLLECTION_CONFIG_FILE);
let af = AtomicFile::new(&config_path, AllowOverwrite);
state_bytes = serde_json::to_vec(self).unwrap();
af.write(|f| f.write_all(&state_bytes))
}
}
资料来源:lib/collection/src/config.rs:30-60
操作类型系统
IssuesReport 问题报告
Qdrant 提供了问题追踪机制,用于报告实例中的所有未解决问题:
#[derive(Serialize, JsonSchema, Debug)]
pub struct IssuesReport {
pub issues: Vec<IssueRecord>,
}
PeerMetadata 对等节点元数据
每个对等节点都维护版本信息,用于集群管理和一致性检查:
#[derive(Clone, Debug, Eq, PartialEq, Hash, Deserialize, Serialize, JsonSchema)]
pub struct PeerMetadata {
pub(crate) version: Version,
}
impl PeerMetadata {
pub fn current() -> Self;
pub fn is_different_version(&self) -> bool;
}
资料来源:lib/collection/src/operations/types.rs:1-80
通用化模式(Generalizer)
用途与设计
Generalizer 是一种特性(Trait),用于从请求结构中移除向量和有效载荷的具体细节,生成轻量级的通用表示:
/// 从结构中移除向量和有效载荷的实现接口
/// 用于泛化请求,去除向量和有效载荷的具体细节
/// 除向量和有效载荷外的其他字段会被复制
/// 向量会被替换为长度指示,有效载荷会被替换为键和长度指示
pub trait Generalizer {
fn remove_details(&self) -> Self;
}
资料来源:lib/collection/src/operations/generalizer/mod.rs:1-30
操作子模块
通用化系统包含以下子模块:
| 子模块 | 功能 |
|---|---|
count | 计数操作通用化 |
facet | 分面搜索操作 |
matrix | 矩阵操作 |
points | 点操作通用化 |
query | 查询操作通用化 |
update_persisted | 持久化更新操作 |
段操作(Segment Operations)
数据一致性检查
Segment 层提供了完整的数据一致性验证功能:
impl Segment {
/// 检查段自身的数据一致性
/// - 存在内部ID但无外部ID
/// - 存在外部ID但无内部ID
/// - 存在内部ID但无版本信息
/// - 存在内部ID但无向量数据
pub fn check_data_consistency(&self) -> OperationResult<()>;
}
资料来源:lib/segment/src/segment/segment_ops.rs:1-50
有效载荷索引管理
段操作还包括有效载荷索引的自动创建和更新:
// 创建或更新与配置不匹配的有效载荷索引
for (key, schema) in schema_config {
match schema_applied.get(key) {
Some(existing_schema) if existing_schema == schema => continue,
Some(existing_schema) => log::warn!(
"段中的有效载荷索引不正确,正在重新创建 (当前: {:?}, 配置: {:?})",
existing_schema.name(),
schema.name(),
),
None => log::warn!(
"段中缺少 {} 有效载荷索引,正在创建",
schema.name(),
),
}
self.create_field_index(...)?;
}
资料来源:lib/segment/src/segment/segment_ops.rs:50-100
HTTP 客户端封装
src/common/http_client 模块提供了 Qdrant 服务间通信的 HTTP 客户端实现,支持请求超时和重试机制。相关改进包括:
- 搜索和点检索超时处理(v1.16.3)
- 遥测和指标请求超时处理(v1.16.2)
- HTTP 请求中添加 User-Agent 头(v1.16.2)
资料来源:src/common/mod.rs:15
API 版本与变更
v1.18.x 改进
- 批量查询优化:全量扫描场景下批量查询速度提升最多 3 倍
- 异步 Upsert 向量维度验证:在 WAL 写入前进行验证
v1.17.x 特性
- 相关性反馈 API(v1.17.0):支持搜索结果相关性反馈
- 优化进度报告 API(v1.17.0):提供详细的优化进度和各阶段信息
- GridStore 非阻塞刷新(v1.17.1):减少搜索尾部延迟
- 延迟点更新应用(v1.17.1):使用
prevent_unoptimized=true优化点更新
v1.16.x 稳定性改进
- 关键 WAL 修复:避免共识破坏或数据损坏
- 启动时主动迁移存储:从 RocksDB 迁移到 GridStore
相关资源
- REST API 文档
- Python 客户端
- JavaScript/TypeScript 客户端
- Java 客户端
- .NET/C# 客户端:https://github.com/qdrant/qdrant-dotnet
失败模式与踩坑日记
保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。
非工程用户可能没有 Docker,启动成本明显增加。
假设不成立时,用户拿不到承诺的能力。
本地安装成功不等于能力可用,外部服务不可用会阻断体验。
新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
Pitfall Log / 踩坑日志
项目:qdrant/qdrant
摘要:发现 8 个潜在踩坑项,其中 0 个为 high/blocking;最高优先级:安装坑 - 依赖 Docker 环境。
1. 安装坑 · 依赖 Docker 环境
- 严重度:medium
- 证据强度:runtime_trace
- 发现:安装/运行入口包含 Docker 命令:docker run -p 6333:6333 qdrant/qdrant
- 对用户的影响:非工程用户可能没有 Docker,启动成本明显增加。
- 建议检查:标注 Docker 前置条件,并提供非 Docker 路径或失败提示。
- 复现命令:
docker run -p 6333:6333 qdrant/qdrant - 防护动作:Docker 前置条件未说明时,不把项目标成普通用户低门槛。
- 证据:identity.distribution | github_repo:268163609 | https://github.com/qdrant/qdrant | docker run -p 6333:6333 qdrant/qdrant
2. 能力坑 · 能力判断依赖假设
- 严重度:medium
- 证据强度:source_linked
- 发现:README/documentation is current enough for a first validation pass.
- 对用户的影响:假设不成立时,用户拿不到承诺的能力。
- 建议检查:将假设转成下游验证清单。
- 防护动作:假设必须转成验证项;没有验证结果前不能写成事实。
- 证据:capability.assumptions | github_repo:268163609 | https://github.com/qdrant/qdrant | README/documentation is current enough for a first validation pass.
3. 运行坑 · 运行可能依赖外部服务
- 严重度:medium
- 证据强度:source_linked
- 发现:项目说明出现 external service/cloud/webhook/database 等运行依赖关键词。
- 对用户的影响:本地安装成功不等于能力可用,外部服务不可用会阻断体验。
- 建议检查:确认是否有离线 demo、mock 数据或可替代服务。
- 防护动作:外部服务依赖未明确时,不把本地安装成功等同于能力可用。
- 证据:packet_text.keyword_scan | github_repo:268163609 | https://github.com/qdrant/qdrant | matched external service / cloud / webhook / database keyword
4. 维护坑 · 维护活跃度未知
- 严重度:medium
- 证据强度:source_linked
- 发现:未记录 last_activity_observed。
- 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
- 建议检查:补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作:维护活跃度未知时,推荐强度不能标为高信任。
- 证据:evidence.maintainer_signals | github_repo:268163609 | https://github.com/qdrant/qdrant | last_activity_observed missing
5. 安全/权限坑 · 下游验证发现风险项
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:下游已经要求复核,不能在页面中弱化。
- 建议检查:进入安全/权限治理复核队列。
- 防护动作:下游风险存在时必须保持 review/recommendation 降级。
- 证据:downstream_validation.risk_items | github_repo:268163609 | https://github.com/qdrant/qdrant | no_demo; severity=medium
6. 安全/权限坑 · 存在评分风险
- 严重度:medium
- 证据强度:source_linked
- 发现:no_demo
- 对用户的影响:风险会影响是否适合普通用户安装。
- 建议检查:把风险写入边界卡,并确认是否需要人工复核。
- 防护动作:评分风险必须进入边界卡,不能只作为内部分数。
- 证据:risks.scoring_risks | github_repo:268163609 | https://github.com/qdrant/qdrant | no_demo; severity=medium
7. 维护坑 · issue/PR 响应质量未知
- 严重度:low
- 证据强度:source_linked
- 发现:issue_or_pr_quality=unknown。
- 对用户的影响:用户无法判断遇到问题后是否有人维护。
- 建议检查:抽样最近 issue/PR,判断是否长期无人处理。
- 防护动作:issue/PR 响应未知时,必须提示维护风险。
- 证据:evidence.maintainer_signals | github_repo:268163609 | https://github.com/qdrant/qdrant | issue_or_pr_quality=unknown
8. 维护坑 · 发布节奏不明确
- 严重度:low
- 证据强度:source_linked
- 发现:release_recency=unknown。
- 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
- 建议检查:确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作:发布节奏未知或过期时,安装说明必须标注可能漂移。
- 证据:evidence.maintainer_signals | github_repo:268163609 | https://github.com/qdrant/qdrant | release_recency=unknown
来源:Doramagic 发现、验证与编译记录