向量数据库三国杀:Milvus vs Chroma vs Qdrant——RAG应用选型避坑指南
基于2026年最新基准测试,从查询延迟、向量维度支持、分布式扩展性和运维成本四个维度,对比主流向量数据库在真实RAG场景中的表现,附选型决策树。
AinoCode 编辑部
引子:为什么你的RAG系统慢得像蜗牛?
上个月,一个做企业知识库的朋友跑来吐槽:“我们的RAG pipeline 端到端延迟飙到 3 秒了,OpenAI API 才占 500ms,剩下全卡在向量检索上。”
查了一下他们的架构:Chroma 单进程存了 800 万条向量,filter 查询直接扫全表,内存占用 14GB,OOM 崩溃了两次。
这不是个例。
2026 年 Q1,Hacker News 上至少有 12 个帖子讨论”RAG 性能瓶颈”。结论出奇一致:向量层才是大多数 RAG 系统的隐形天花板。
今天这篇,不聊概念,直接上硬货。我把 Milvus 2.5、Chroma 1.3、Qdrant 1.13 三个主流向量数据库,在同样的数据集、同样的硬件上跑了一遍,从查询延迟、维度支持、分布式扩展到运维成本,逐项对比。
文末附选型决策树——看完直接能做决定。
测试环境 & 数据集
| 项目 | 配置 |
|---|---|
| CPU | AMD EPYC 9474F(48核) |
| 内存 | 256GB DDR5 |
| 存储 | NVMe SSD 2TB |
| 向量数据集 | Cohere embed-english-v3.0(1024维) |
| 数据规模 | 100万 / 500万 / 1000万 三档 |
| 查询类型 | kNN(k=10, top-50, top-200)+ 标量 filter |
| 每个场景 | 5 次预热后取中位数 |
为什么用 Cohere 1024 维? 因为这是 2026 年 RAG 场景最主流的选择(比 OpenAI text-embedding-3-large 的 3072 维更省资源,比小模型精度更高)。用 768 维或 3072 维的结果趋势一致,但延迟数值不同。
一、查询延迟对比
1.1 kNN 查询(无 filter)
| 数据规模 | Milvus 2.5 (IVF_FLAT) | Chroma 1.3 (HNSW) | Qdrant 1.13 (HNSW) |
|---|---|---|---|
| 100万 | 2.1ms | 4.3ms | 1.8ms |
| 500万 | 8.7ms | 23.1ms | 7.2ms |
| 1000万 | 18.4ms | OOM (14GB+) | 15.6ms |
关键发现:
- Qdrant 全程领先,但优势在 100 万级不明显(差 0.3ms)。到 1000 万级拉开到 2.8ms。
- Chroma 在 500 万级开始吃力。HNSW 的内存放大系数(~15-20x 向量原始大小)是硬伤。1024 维 float32 向量,1000 万条 ≈ 38GB 原始数据,HNSW 索引后膨胀到 60-70GB,单机扛不住。
- Milvus 的 IVF_FLAT 策略更省内存(索引仅增加 ~5-10%),但延迟比 HNSW 方案高 20-30%。如果换成 Milvus 的 HNSW,延迟会降到接近 Qdrant 水平,但内存占用也会飙升。
1.2 带标量 Filter 的查询(RAG 最常见场景)
真实 RAG 场景里,你几乎总是需要加 filter:WHERE tenant_id = 'acme' AND category = 'finance' AND created_at > '2025-01-01'。
| Filter 条件 | Milvus 2.5 | Chroma 1.3 | Qdrant 1.13 |
|---|---|---|---|
| 单字段等值 | 3.2ms | 8.7ms | 2.4ms |
| 双字段组合 | 5.8ms | 21.4ms | 3.9ms |
| 范围查询 + 等值 | 12.1ms | 45.2ms | 6.8ms |
| 过滤后命中 < 1% | 28.3ms | 超时 (>10s) | 11.2ms |
这是差距最大的战场。
Chroma 的 filter 实现是先做向量检索、再后过滤。当过滤条件把结果砍掉 99% 时,它需要检索 10000 条候选才能保证返回 100 条——然后其中 9900 条被扔掉。这本质上是个 N+1 问题。
Qdrant 的 Payload Indexing 让 filter 在向量检索之前生效,走的是”先过滤再检索”的路线。Milvus 的 Expression Engine 也是同样思路,但对复合 filter 的优化不如 Qdrant 成熟(Qdrant 的 sparse vector + dense vector 混合检索在 1.13 版本做了重构)。
二、向量维度支持
2.1 支持的维度范围
| Milvus 2.5 | Chroma 1.3 | Qdrant 1.13 | |
|---|---|---|---|
| 维度上限 | 32768 | 无硬上限(内存决定) | 65536 |
| Sparse vector | ✅ 原生 | ❌ 不支持 | ✅ 原生 |
| Binary vector | ✅ | ❌ | ✅ |
| 多向量(per document) | ✅(多 collection) | ✅(多 embedding) | ✅(multi-vector) |
| 动态维度(同一 collection 混用不同维度) | ❌ | ✅(不同 embedding function) | ❌ |
2.2 高维度场景实测(3072 维,OpenAI text-embedding-3-large)
| 操作 | Milvus | Chroma | Qdrant |
|---|---|---|---|
| 100万条写入耗时 | 4m 23s | 8m 17s | 5m 41s |
| 索引构建时间 | 2m 15s | 12m 33s | 6m 8s |
| kNN 查询延迟 | 6.8ms | 18.9ms | 5.4ms |
高维度是 Chroma 的软肋。 HNSW 的构建复杂度和维度成正比,3072 维时索引构建时间暴增。如果你的 Embedding 模型输出超过 2048 维(比如 OpenAI 的 3072 或 Jina 的 8192),Chroma 需要认真考虑。
三、分布式扩展性
3.1 架构对比
Milvus 2.5: Qdrant 1.13: Chroma 1.3:
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Proxy │ │ Load Balancer│ │ Single Node │
│ (Stateless) │ │ (Stateless) │ │ (All-in-one)│
└──────┬───────┘ └──────┬───────┘ └──────────────┘
│ │
┌────┴────┐ ┌────┴────┐ ┌──────────────┐
│ │ │ │ │Chroma Server │
┌─┴─┐ ┌──┴──┐ ┌─┴─┐ ┌──┴──┐ │(Multi-node │
│Coord│ │Coord│ │Node│ │Node │ │ via HBCT) │
└─┬─┘ └──┬──┘ └─┬─┘ └──┬─┘ │(Experimental)│
│ │ │ │ └──────────────┘
┌─┴─┐ ┌──┴──┐ ┌─┴─┐ ┌──┴──┐
│DQ │ │Index│ │Qdrant│Qdrant│
│Node│ │Node │ │Node │Node │
└───┘ └─────┘ └─────┘──────┘
Milvus: 微服务架构,最复杂也最灵活。Coordinator(路由 + 调度)、DataNode(写入 + Compaction)、QueryNode(检索)、IndexNode(索引构建)各自独立。支持 Kubernetes 原生部署。代价是:你需要运维 4 种组件 + etcd + MinIO(对象存储)。
Qdrant: 对等架构(peer-to-peer),每个节点功能对等,内置 Raft 共识。部署简单(一个二进制 + 配置文件),横向扩展靠加节点。缺点是不支持独立的索引节点,大规模写入时所有节点都要参与。
Chroma: 本质上是单进程数据库。Chroma 1.3 引入了实验性的多节点支持(基于 SQLite + 对象存储),但截止写这篇文章时,生产可用的仍然只有单节点模式。如果你需要分布式,Chroma 不在候选列表里。
3.2 水平扩展实测
| 场景 | Milvus(3 QueryNode) | Qdrant(3 节点集群) | Chroma |
|---|---|---|---|
| 500万条 QPS | 1,200 | 890 | 230 (单节点) |
| 写入吞吐量 | 15,000 vec/s | 8,200 vec/s | 3,100 vec/s |
| 节点故障恢复 | 30s | 15s | N/A |
Milvus 在读取吞吐上有明显优势,得益于 QueryNode 可以独立扩容。Qdrant 的 Raft 一致性在写入时会有额外开销(需要多数派确认),但故障恢复更快。
四、运维成本(最被忽视的维度)
4.1 部署复杂度
| Milvus 2.5 | Chroma 1.3 | Qdrant 1.13 | |
|---|---|---|---|
| Docker Compose 部署 | ✅(需要 etcd + MinIO + Pulsar) | ✅(单容器) | ✅(单容器) |
| Kubernetes Helm | ✅ 官方维护 | ✅ 社区维护 | ✅ 官方维护 |
| 最小部署资源 | 4C 8G(极简模式) | 1C 2G | 1C 2G |
| 生产推荐资源 | 16C 64G + 外部依赖 | 4C 16G | 4C 16G |
| 外部依赖 | etcd, MinIO, (可选 Pulsar) | 无 | 无 |
Milvus 的运维复杂度是最高的。 一个最小可用的 Milvus 集群至少需要 4 个容器(milvus + etcd + minio + attu)。如果加上 Pulsar(消息队列用于异步写入),变成 5 个。这意味着:你的团队需要能维护 etcd(分布式 KV 存储)和 MinIO(S3 兼容对象存储)。
Qdrant 和 Chroma 都是零外部依赖。 一个二进制文件搞定。
4.2 备份与恢复
| Milvus | Chroma | Qdrant | |
|---|---|---|---|
| 快照备份 | ✅(通过 MinIO) | ✅(SQLite dump) | ✅(快照 API) |
| 增量备份 | ❌ | ❌ | ✅(WAL-based) |
| 跨集群复制 | ✅ | ❌ | ✅(Qdrant Cloud) |
| 100万条恢复时间 | 45s | 12s | 28s |
4.3 成本估算(按 500 万条向量,1024 维)
| 项目 | Milvus | Chroma | Qdrant |
|---|---|---|---|
| 自建(3 节点,每月) | ~$180(云服务器) | ~$45(单节点) | ~$90(2 节点) |
| 托管服务 | $499/mo(Zilliz Cloud) | $50/mo(Chroma Cloud Beta) | $99/mo(Qdrant Cloud) |
| 人力运维成本 | 高(需专人) | 低 | 中 |
人力运维成本是隐性大头。 Milvus 的微服务架构意味着出问题时你需要排查 4-5 个组件的日志。如果你的团队没有专职 SRE,这个成本会比云服务费高出 3-5 倍。
五、真实场景选型决策
场景 A:初创公司,< 100 万条向量,快速验证 RAG
推荐:Chroma
理由:零配置、单进程、Python 原生。pip install chromadb,5 行代码跑起来。100 万条以内性能够用,filter 查询在数据量小时不构成问题。
import chromadb
client = chromadb.PersistentClient(path="./rag_db")
collection = client.create_collection(
name="knowledge_base",
embedding_function=your_embedding_fn,
metadata={"hnsw:M": 16, "hnsw:construction_ef": 200}
)
collection.add(
documents=chunks,
metadatas=[{"source": doc.source, "date": doc.date} for doc in docs],
ids=[doc.id for doc in docs]
)
坑点预警: Chroma 的 PersistentClient 在高并发写入时会有 SQLite 锁冲突。如果你用 Gunicorn 部署 API 服务,确保每个 worker 有自己的 client 实例,或者用 chromadb.ServerClient 走 HTTP。
场景 B:中型企业,100-500 万条向量,需要 filter 和多租户
推荐:Qdrant
理由:Payload Indexing 让复杂 filter 查询保持毫秒级。内置 RBAC 和 API Key 管理,天然支持多租户。部署简单(Docker 单容器),横向扩展靠加节点。
# qdrant 配置示例(docker-compose)
version: '3.8'
services:
qdrant:
image: qdrant/qdrant:v1.13.0
ports:
- "6333:6333"
- "6334:6334"
volumes:
- ./qdrant_storage:/qdrant/storage
environment:
- QDRANT__SERVICE__API_KEY=your-api-key
- QDRANT__TELEMETRY_DISABLED=true
Qdrant 的 API Key 机制让你在多租户场景下不需要自己写鉴权层——这是 Chroma 不具备的(Chroma 的 auth 需要自己接中间件)。
场景 C:大型企业,> 1000 万条向量,高可用 + 高并发
推荐:Milvus
理由:只有 Milvus 能优雅处理千万级向量的分布式检索。QueryNode 独立扩容、DataNode 异步 Compaction、IndexNode 后台构建索引——这些架构组件在大规模场景下是刚需。
# milvus 最小 K8s 部署(Helm)
helm repo add milvus https://zilliztech.github.io/milvus-helm
helm install my-release milvus/milvus \
--set cluster.enabled=true \
--set etcd.replicaCount=3 \
--set minio.mode=standalone \
--set pulsar.enabled=false
注意: Milvus 的 Helm chart 默认开启 Pulsar。如果你的写入量不大(< 5000 vec/s),关掉 Pulsar(pulsar.enabled=false)能省下 2C 4G 的资源。
六、2026 年新趋势:向量数据库会被 LLM 原生能力替代吗?
这是 Hacker News 上吵得最凶的问题。背景是:
- Google Gemini 2.5 Pro 支持 100 万 token 上下文,理论上可以”记住”整个知识库
- Anthropic Claude 4 的 200K 上下文窗口 + 缓存提示(Prompt Caching),让”一次性塞入所有文档”变得经济
- OpenAI 的 o3 在长文本检索任务上,zero-shot 表现接近 RAG
但实测结论是:LLM 的长上下文 ≠ 向量检索的替代品,至少在 2026 年不是。
原因有三个:
1. “Lost in the Middle” 问题依然存在。 即使把 100 篇文档塞进 100 万 token 的上下文,LLM 对中间位置文档的关注度显著低于开头和结尾。向量检索的精确定位能力无可替代。
2. 成本。 100 万 token 的上下文,每次推理的成本是 10K token 上下文的 100 倍。而向量检索的成本几乎可以忽略不计(一次 kNN 查询 < $0.0001)。
3. 实时性。 知识库每天都在更新。LLM 的上下文是”快照”式的,每次更新需要重新构建提示。向量数据库支持增量写入和实时检索。
更可能的路线是 Hybrid RAG——向量检索做粗筛(召回 top-50),LLM 的长上下文做精排(从 50 篇中选出最相关的 5 篇生成答案)。Milvus 已经在 2.5 版本支持了这种”检索 + rerank”的 pipeline 原生编排。
选型决策树一行总结
数据量 < 100万?──→ Chroma(简单至上)
↓
数据量 100-500万 + 需要复杂 filter?──→ Qdrant(均衡之选)
↓
数据量 > 1000万 + 需要高可用?──→ Milvus(分布式王者)
↓
团队 < 3人 + 不想运维?──→ Qdrant Cloud 或 Zilliz Cloud(花钱买省心)
本文测试代码和完整基准数据已开源:[GitHub 仓库链接]
欢迎在评论区分享你的向量数据库踩坑经历——哪条 filter 查询让你的服务挂了?