引言
Milvus 是当前最流行的开源分布式向量数据库,专为大规模向量检索场景设计。相比 Pinecone(全托管)和 Chroma(轻量级),Milvus 的优势在于:分布式架构、百亿级向量支持、丰富的索引类型和灵活的部署方式。
┌────────────────────────────────────────────────────────────┐
│ Milvus 分布式架构 │
├────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ SDK │ │ SDK │ │ SDK │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ └────────────┼────────────┘ │
│ ▼ │
│ ┌────────────────┐ │
│ │ Proxy 节点 │ (负载均衡 + 请求路由) │
│ └───────┬────────┘ │
│ │ │
│ ┌──────────┴──────────┐ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Query节点 │ │ Index节点 │ │
│ │ (检索服务) │ │ (索引构建) │ │
│ └──────┬──────┘ └──────┬───────┘ │
│ │ │ │
│ └─────────┬─────────┘ │
│ ▼ │
│ ┌────────────────┐ │
│ │ Data节点 │ (数据持久化) │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ 对象存储/S3 │ (Etcd + MinIO/S3) │
│ └────────────────┘ │
└────────────────────────────────────────────────────────────┘
一、核心架构组件
| 组件 | 角色 | 说明 |
|---|
| Proxy | 接入层 | 请求路由、负载均衡、权限校验 |
| Query | 检索层 | 执行向量检索、标量过滤 |
| Index | 索引层 | 构建和管理向量索引(CPU/GPU) |
| Data | 数据层 | 数据持久化、增量/全量合并 |
| Etcd | 元数据管理 | 集群协调、节点发现 |
| MinIO/S3 | 存储层 | 数据文件和索引文件持久化 |
二、部署方案
2.1 Docker Compose(开发/测试)
# docker-compose.yml
version: '3.5'
services:
etcd:
image: quay.io/coreos/etcd:v3.5.5
environment:
- ETCD_AUTO_COMPACTION_MODE=revision
- ETCD_AUTO_COMPACTION_RETENTION=1000
- ETCD_QUOTA_BACKEND_BYTES=4294967296
minio:
image: minio/minio:RELEASE.2023-03-20T20-16-18Z
environment:
MINIO_ACCESS_KEY: minioadmin
MINIO_SECRET_KEY: minioadmin
volumes:
- ./volumes/minio:/minio_data
command: minio server /minio_data
milvus:
image: milvusdb/milvus:v2.4.0
command: ["milvus", "run", "standalone"]
environment:
ETCD_ENDPOINTS: etcd:2379
MINIO_ADDRESS: minio:9000
ports:
- "19530:19530"
depends_on:
- etcd
- minio
volumes:
minio_data:
2.2 Kubernetes 生产部署
# milvus-helm-values.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: milvus-config
data:
milvus.yaml: |
proxy:
port: 19530
timeTickInterval: 200
rootCoord:
port: 53100
queryCoord:
port: 53101
enableActiveStandby: true
indexCoord:
port: 53102
dataCoord:
port: 53103
---
# Helm 安装
# helm repo add milvus https://milvus-io.github.io/milvus-helm/
# helm install my-milvus milvus/milvus \
# --set cluster.enabled=true \
# --set persistence.enabled=true \
# --set persistence.storageClass=gp2
三、索引类型与选择
3.1 Milvus 支持的索引
| 索引类型 | 算法 | 适用场景 | 精度 | 构建速度 | 内存占用 |
|---|
| IVF_FLAT | 倒排索引 | 精度优先 | 高 | 快 | 高 |
| IVF_SQ8 | 量化索引 | 内存优先 | 中 | 快 | 低 |
| IVF_PQ | 乘积量化 | 极致压缩 | 低 | 中 | 极低 |
| HNSW | 分层导航图 | 速度优先 | 极高 | 慢 | 极高 |
| DISKANN | 磁盘索引 | 超大容量 | 高 | 慢 | 低 |
| AUTOINDEX | 自动选择 | 简化管理 | 最佳 | 自动 | 动态 |
3.2 索引选择示例
from pymilvus import (
connections, Collection, FieldSchema,
CollectionSchema, DataType, IndexType
)
# 创建集合
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=768),
FieldSchema(name="title", dtype=DataType.VARCHAR, max_length=256),
FieldSchema(name="category", dtype=DataType.VARCHAR, max_length=64),
FieldSchema(name="content", dtype=DataType.VARCHAR, max_length=65535),
]
schema = CollectionSchema(fields, description="RAG文档集合")
collection = Collection(name="rag_docs", schema=schema)
# 创建 HNSW 索引(推荐用于高精度检索)
index_params = {
"metric_type": "COSINE",
"index_type": "HNSW",
"params": {
"M": 16, # 每个节点的最大连接数(8-64)
"efConstruction": 200 # 构建时的搜索范围(100-500)
}
}
collection.create_index(
field_name="embedding",
index_params=index_params
)
3.3 索引参数调优
def choose_index_params(
total_vectors: int,
memory_gb: int,
precision_requirement: str
) -> dict:
"""根据场景推荐索引参数"""
params = {
"metric_type": "COSINE"
}
if total_vectors < 1_000_000:
params["index_type"] = "HNSW"
params["params"] = {"M": 16, "efConstruction": 200}
elif total_vectors < 10_000_000:
if memory_gb >= 64:
params["index_type"] = "HNSW"
params["params"] = {"M": 24, "efConstruction": 300}
else:
params["index_type"] = "IVF_SQ8"
params["params"] = {"nlist": 4096}
else:
params["index_type"] = "DISKANN"
params["params"] = {}
return params
四、数据操作
4.1 写入与插入
import numpy as np
from pymilvus import Collection, utility
# 连接
connections.connect(
host="localhost",
port="19530",
alias="default"
)
# 插入数据
collection = Collection("rag_docs")
collection.load()
def batch_insert(
collection,
embeddings: np.ndarray,
texts: list[str],
metadata: list[dict],
batch_size: int = 1000
):
"""批量插入数据"""
total = len(embeddings)
for i in range(0, total, batch_size):
end = min(i + batch_size, total)
mr = collection.insert([
list(range(i, end)),
embeddings[i:end].tolist(),
[m["title"] for m in metadata[i:end]],
[m["category"] for m in metadata[i:end]],
texts[i:end]
])
print(f"已插入 {end}/{total}, 耗时: {mr}")
collection.flush()
4.2 检索查询
def search_with_params(
collection: Collection,
query_vector: list[float],
top_k: int = 10,
expr: str = None,
params: dict = None
):
"""带参数的高级检索"""
search_params = params or {
"metric_type": "COSINE",
"params": {"ef": 64} # HNSW 搜索宽度
}
results = collection.search(
data=[query_vector],
anns_field="embedding",
param=search_params,
limit=top_k,
expr=expr, # 标量过滤表达式
output_fields=["title", "category", "content"]
)
for hit in results[0]:
print(f"距离: {hit.distance:.4f}")
print(f"内容: {hit.entity.get('title')}")
print(f"类别: {hit.entity.get('category')}")
return results
4.3 混合检索(向量 + 标量过滤)
# 类别过滤 + 向量检索
results = search_with_params(
collection,
query_vector,
top_k=10,
expr='category in ["technology", "science"]',
params={"metric_type": "COSINE", "params": {"ef": 64}}
)
# 范围过滤
results = search_with_params(
collection,
query_vector,
top_k=10,
expr='id > 1000'
)
五、生产运维
5.1 性能优化
| 优化项 | 配置 | 效果 |
|---|
| 增加 Query 节点数 | queryNode.replicas: 3 | 提升并发查询能力 |
| 使用 GPU 索引 | indexNode.enableGPU: true | 加速索引构建 |
| 调整 Segment 大小 | dataCoord.segment.maxSize: 2048 | 减少小文件 |
| 启用压缩 | dataCoord.compaction.enable: true | 优化存储利用率 |
| 缓存预热 | 预加载热点集合 | 减少冷启动延迟 |
5.2 监控告警
# 启用 Prometheus 监控
helm install prometheus prometheus-community/kube-prometheus-stack \
--set grafana.enabled=true
# Milvus 内置指标
# - query latency (P50/P95/P99)
# - index build duration
# - memory/disk usage per node
# - request QPS
# - cache hit ratio
5.3 数据备份
# 创建快照
from pymilvus import utility
# 备份集合
utility.create_snapshot(
collection_name="rag_docs",
backup_name="daily_backup_20250509"
)
# 列出备份
print(utility.list_snapshots(collection_name="rag_docs"))
六、扩缩容
# 水平扩展 Query 节点
helm upgrade my-milvus milvus/milvus \
--set queryNode.replicas=5
# 扩缩存储(调整 Data 节点)
helm upgrade my-milvus milvus/milvus \
--set dataNode.replicas=3
# 垂直扩展(调整资源)
helm upgrade my-milvus milvus/milvus \
--set queryNode.resources.requests.memory=16Gi \
--set queryNode.resources.limits.memory=32Gi
七、Milvus 适用场景对比
| 场景 | Milvus | Pinecone | Chroma |
|---|
| 百亿级向量 | ✅ 最佳 | ❌ 成本高 | ❌ 不支持 |
| 自建私有云 | ✅ 完美 | ❌ 不支持 | ✅ 但有限 |
| 快速原型 | ❌ 部署复杂 | ✅ 最佳 | ✅ 最佳 |
| 混合检索 | ✅ 丰富 | ✅ 中等 | ❌ 基础 |
| GPU 加速 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 |
| 多租户 | ✅ 支持 | ✅ 支持 | ❌ 不支持 |
八、总结
Milvus 最适合的场景:
- 大规模向量检索(百万到百亿级)
- 企业自建私有云,对数据主权有要求
- 复杂检索需求(混合检索、多向量字段)
- 有 Kubernetes 运维能力的团队
- 对性能和扩展性有极致要求
相关资源: