前言
当你的 RAG 系统需要处理百万级以上向量时,单机版的向量检索就不够用了。你需要一个真正的向量数据库。
目前主流的三个选择是:Milvus、Qdrant、Chroma。本文从架构、性能、功能、运维四个维度深度对比。
架构对比
Milvus(云原生)
┌──────────┐ ┌──────────┐ ┌──────────┐ │ Proxy │ │ Proxy │ │ Proxy │ ← 无状态网关 └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ ┌────▼─────────────▼─────────────▼────┐ │ Root Coordinator │ ← 元数据管理 └────▲─────────────▲─────────────▲────┘ │ │ │ ┌────┴─────┐ ┌────┴─────┐ ┌────┴─────┐ │ Query │ │ Data │ │ Index │ │ Node │ │ Node │ │ Node │ ← 计算存储分离 └──────────┘ └──────────┘ └──────────┘ 依赖:etcd(元数据)+ MinIO/S3(数据)+ Kafka(日志)特点:组件多、功能全、扩展性强。适合大规模生产环境。
Qdrant(Rust 实现)
┌──────────────┐ │ Qdrant │ │ ┌────────┐ │ │ │ Segment│ │ ← 每个 collection 分为多个 segment │ │ │ │ │ │ HNSW │ │ ← 向量索引 + 负载索引 │ │ + Payload│ │ │ └────────┘ │ └──────────────┘ 单二进制文件部署,无外部依赖。特点:Rust 实现、性能卓越、部署极简。单二进制搞定一切。
Chroma(轻量级)
┌──────────────┐ │ Chroma │ │ ┌────────┐ │ │ │SQLite │ │ ← 数据持久化 │ │+ HNSW │ │ ← 内存向量索引 │ └────────┘ │ └──────────────┘ pip install chromadb 即可使用。特点:极简、开发友好、不适合生产大规模场景。
性能基准
测试条件:100 万 768 维向量,余弦距离,Top-10 检索,单机(32 核,128GB RAM,NVMe SSD)
| 指标 | Milvus 2.4 | Qdrant 1.9 | Chroma 0.5 |
|---|---|---|---|
| 写入速度(向量/秒) | 8,000 | 12,000 | 5,000 |
| 查询延迟(P50) | 8ms | 3ms | 5ms |
| 查询延迟(P99) | 25ms | 12ms | 30ms |
| QPS(单机) | 1,200 | 2,500 | 800 |
| 内存占用 | 2.8GB | 1.5GB | 3.2GB |
| 索引构建时间 | 12min | 8min | 15min |
注意:这是单机测试。Milvus 的强项在分布式,多节点下 QPS 可以线性扩展。
核心功能对比
标量过滤(Filter Search)
这是向量数据库最重要的实用功能——先按标签筛选,再搜向量。
# Milvusmilvus_client.search(collection_name="docs",data=[query_vector],limit=10,expr="category == 'technology' && view_count > 1000",)# Qdrantqdrant_client.search(collection_name="docs",query_vector=query_vector,limit=10,query_filter=models.Filter(must=[models.FieldCondition(key="category",match=models.MatchValue(value="technology")),models.FieldCondition(key="view_count",range=models.Range(gte=1000)),]),)# Chromachroma_collection.query(query_embeddings=[query_vector],n_results=10,where={"category":"technology","view_count":{"$gte":1000}},)标量过滤性能:
- Qdrant > Milvus > Chroma
- Qdrant 的 payload 索引用内存维护,过滤几乎无开销
- Milvus 在复杂过滤条件下延迟会明显上升
- Chroma 在 10 万级数据以上过滤性能急剧下降
混合检索(Hybrid Search)
# Qdrant —— 原生支持fromqdrant_clientimportQdrantClientfromqdrant_client.modelsimport(HybridFusion,FusionQuery,Prefetch,)qdrant_client.search(collection_name="docs",query_vector=QueryVector(FusionQuery(prefetch=[Prefetch(query=query_vector,limit=50,),Prefetch(query="search keywords",limit=50,),],fusion=HybridFusion.RRF,)),limit=10,)# Milvus —— 需要自己实现混合# 分别做向量检索和 BM25 检索,然后 RRF 合并在应用层Qdrant 是三者中唯一原生支持混合检索的,Milvus 和 Chroma 需要在应用层手动实现 RRF 合并。
数据持久化与备份
| 功能 | Milvus | Qdrant | Chroma |
|---|---|---|---|
| 持久化 | S3/MinIO | 本地磁盘/S3 | SQLite |
| 快照备份 | ✅ 原生 | ✅ 原生 | ❌ 手动 |
| 增量备份 | ✅ | ✅ | ❌ |
| 从备份恢复 | ✅ | ✅ | ❌ |
部署运维
部署复杂度
Milvus: docker-compose 启动 7 个服务 Qdrant: docker run qdrant/qdrant Chroma: pip install chromadb资源占用
| 场景 | Milvus | Qdrant | Chroma |
|---|---|---|---|
| 最小部署 | 4GB RAM + 4 核 | 512MB RAM + 1 核 | 256MB RAM |
| 生产推荐 | 32GB RAM + 16 核 | 8GB RAM + 4 核 | 不推荐生产 |
| 存储 | MinIO 独立 | 直接在磁盘 | SQLite 文件 |
实战部署(Docker Compose)
Qdrant(最轻量):
# docker-compose.ymlservices:qdrant:image:qdrant/qdrant:latestports:-"6333:6333"-"6334:6334"volumes:-./qdrant_storage:/qdrant/storageenvironment:-QDRANT__SERVICE__GRPC_PORT=6334Milvus(生产级):
# docker-compose.ymlservices:etcd:image:quay.io/coreos/etcd:v3.5.5minio:image:minio/minio:latestmilvus:image:milvusdb/milvus:v2.4.0ports:["19530:19530"]depends_on:[etcd,minio]选型决策树
你的场景是? ├── 原型验证 / 学习 / 数据量 < 10 万 │ └── Chroma(最简、最快上手) │ ├── 生产环境 / 数据量 10 万 - 1000 万 │ ├── 需要极简部署、高性能 → Qdrant │ ├── 需要混合检索原生支持 → Qdrant │ └── 需要分布式扩展 → Milvus │ ├── 生产环境 / 数据量 > 1000 万 │ └── Milvus(唯一成熟的分布式方案) │ ├── 需要标量过滤(Filter Search) │ └── Qdrant > Milvus > Chroma │ └── 边缘设备 / 嵌入式场景 └── Qdrant(Rust 编译,二进制仅 30MB)迁移方案
从 Chroma 迁移到 Qdrant:
# 导出 Chroma 数据importchromadb chroma_client=chromadb.PersistentClient(path="./chroma_data")collection=chroma_client.get_collection("docs")all_data=collection.get(include=["embeddings","documents","metadatas"])# 导入到 Qdrantfromqdrant_clientimportQdrantClientfromqdrant_client.modelsimportPointStruct qdrant=QdrantClient("localhost:6333")qdrant.create_collection(collection_name="docs",vectors_config=models.VectorParams(size=768,distance=models.Distance.COSINE),)points=[PointStruct(id=idx,vector=emb.tolist(),payload={"text":all_data["documents"][idx],**all_data["metadatas"][idx]},)foridx,embinenumerate(all_data["embeddings"])]qdrant.upsert(collection_name="docs",points=points)总结
- 快速原型:Chroma(pip install 一秒上手)
- 生产单机:Qdrant(高性能、极简运维、混合检索原生支持)
- 生产分布式:Milvus(功能最全、扩展性最强)
- 核心关注点:标量过滤性能 > 检索精度 > 写入速度 > 部署复杂度
我的个人建议:大部分团队从 Qdrant 开始。它用 Rust 实现,单机性能碾压,运维几乎零成本,需要扩展时也支持分布式。
觉得有用?点赞 + 收藏 + 关注。