【向量数据库】Milvus:为大规模、高性能而生的企业级向量数据库

Milvus:为大规模、高性能而生的企业级向量数据库

  • Milvus:为大规模、高性能而生的企业级向量数据库
    • 一、亿级向量的主流方案
    • 二、Milvus原理与基础
      • [2.1 Milvus 解决了什么问题](#2.1 Milvus 解决了什么问题)
      • [2.2 整体架构:四层分离的设计哲学](#2.2 整体架构:四层分离的设计哲学)
      • [2.3 数据组织:Collection → Partition → Segment](#2.3 数据组织:Collection → Partition → Segment)
      • [2.4 索引原理:三种主流 ANN 索引](#2.4 索引原理:三种主流 ANN 索引)
        • [2.4.1 IVF(Inverted File)------ 基于聚类的倒排](#2.4.1 IVF(Inverted File)—— 基于聚类的倒排)
        • [2.4.2 HNSW(Hierarchical Navigable Small World)------ 基于图的导航](#2.4.2 HNSW(Hierarchical Navigable Small World)—— 基于图的导航)
        • [2.4.3 ANNOY ------ 基于树的分割](#2.4.3 ANNOY —— 基于树的分割)
      • [2.5 一致性与隔离级别](#2.5 一致性与隔离级别)
    • 三、方案与对比
      • [3.1 ChromaDB vs Milvus:何时升级](#3.1 ChromaDB vs Milvus:何时升级)
      • [3.2 索引类型选型](#3.2 索引类型选型)
    • 四、实战步骤
      • [4.1 step 1:部署模式选择](#4.1 step 1:部署模式选择)
      • [4.2 step 2:关键代码(Python SDK)](#4.2 step 2:关键代码(Python SDK))
      • [4.3 step 3:插入与检索](#4.3 step 3:插入与检索)
      • [4.4 step 4:关键配置(生产避坑)](#4.4 step 4:关键配置(生产避坑))
      • [4.5 step 5:验证手段](#4.5 step 5:验证手段)
    • 五、总结
    • 系列导航
    • 参考资料

Milvus:为大规模、高性能而生的企业级向量数据库

当向量规模从百万级迈向十亿级,单机数据库的"内存装不下、CPU 算不动"会成为第一个拦路虎。


一、亿级向量的主流方案

让我们从问题出发:

1、我们要"在十亿级别的商品向量里,为一个用户实时找出最相似的 100 个商品"这个方法最关键的部分是什么?

  • 最关键的部分是分布式架构 + 高效索引。十亿向量无法装入单机内存,必须把数据切片到多台机器;与此同时,要在毫秒级返回结果,必须借助近似最近邻(ANN)索引。

2、当流量从 1k QPS 涨到 100k QPS 时,向量检索服务如何不被打垮?

  • 需要计算与存储分离 + 多副本 + 一致性可调。在请求高峰时扩出更多 QueryNode 处理查询请求,而数据本身只需在多个副本间复制即可。

3、当某个查询节点宕机时,正在处理的请求怎么办?数据会不会丢?

  • 需要故障转移 + 多副本机制。Milvus 通过 etcd 做服务发现、K8s 调度 + 健康检查做故障转移、Pulsar/Kafka 做写入恢复,保证节点宕机不影响查询和数据不丢。

在实际生产中,向量数据规模往往远超预期:电商商品、日志、文档、图片、用户行为,每一类动辄千万起步。当我们把 ChromaDB 这类轻量库用到一定规模时,"插入变慢""查询超时""内存爆掉"会接踵而来。Milvus 正是为这种场景而生的解决方案

官方文档:https://milvus.io/docs/zh/overview.md


二、Milvus原理与基础

Milvus 是由 Zilliz 公司创建并贡献给 LF AI & Data 基金会的开源向量数据库。它的设计目标非常明确:处理十亿乃至万亿级向量、毫秒级响应、企业级可靠性。要理解这三点,我们先从架构开始拆解。

2.1 Milvus 解决了什么问题

  1. 大规模向量数据的存储和检索 :当数据量达到数十亿甚至更多时,单节点数据库会遇到性能瓶颈。Milvus 采用分布式架构,可以将计算和存储资源分开,并根据需求进行水平扩展,从而轻松应对海量数据的挑战。

  2. 高并发和低延迟的查询需求:对于需要同时处理成千上万用户请求的在线服务(例如电商的推荐系统),Milvus 能够通过其分布式的特性,保证在高并发下依然有非常低的查询延迟。

  3. 企业级的可靠性和高级功能:Milvus 提供了数据备份、数据副本、故障转移和可调的一致性级别等高级功能,确保了生产环境下的高可用性和数据可靠性。

2.2 整体架构:四层分离的设计哲学

Milvus 自 2.0 之后采用了存算分离的微服务架构。理解这张图,是后续做容量规划、问题排查的前提。

复制代码
┌─────────────────────────────────────────────────────┐
│  Access Layer(接入层)                              │
│  - Proxy:无状态网关,负责请求路由、鉴权、限流         │
├─────────────────────────────────────────────────────┤
│  Coordinator Service(协调层)                        │
│  - Root Coord:管理集合(Collection)元数据            │
│  - Query Coord:管理查询节点、负载均衡、Segment 分配  │
│  - Data Coord:管理数据节点、数据写入、Compaction     │
│  - Index Coord:管理索引构建任务                      │
├─────────────────────────────────────────────────────┤
│  Worker Node(执行层)                                │
│  - QueryNode:执行向量检索与标量过滤                  │
│  - DataNode:处理写入、构建日志索引                    │
│  - IndexNode:异步构建向量索引                        │
├─────────────────────────────────────────────────────┤
│  Storage Layer(存储层)                              │
│  - Meta Store (etcd):元数据                          │
│  - Log Broker (Pulsar/Kafka):写入日志                │
│  - Object Storage (S3/MinIO):向量与索引的持久化       │
└─────────────────────────────────────────────────────┘

我们来逐层解读这张图

  • 接入层是无状态的 Proxy,可以无限水平扩展------这是应对百万 QPS 的关键。
  • 协调层 是"大脑",4 个 Coord 各司其职,通过 etcd 选主。etcd 挂了整个集群就瘫了,所以生产环境必须部署 3 节点 etcd 集群。
  • 执行层做实际工作。QueryNode 和 DataNode 也是无状态的,K8s 拉起 / 杀掉的代价很低。
  • 存储层 用对象存储(S3/MinIO)存真正的向量数据。这与 Elasticsearch 的设计哲学类似------让内存和 CPU 去服务查询,磁盘做冷数据兜底

注意:Milvus 的存算分离不是"为了分离而分离",而是因为向量检索的查询负载(计算密集)和写入负载(IO 密集)特征完全不同。把它们解耦后,扩缩容策略可以独立设计。

2.3 数据组织:Collection → Partition → Segment

Milvus 把数据组织成三层结构,这是排查"为什么查得慢""为什么插入卡住"的基础。

层级 概念 作用 类比
Collection 业务表 一类向量的容器,如 product_embeddings 关系数据库的 Table
Partition 分区 按业务维度切分数据,如按时间/类别 分区表
Segment 物理存储单元,达到阈值后封存、构建索引 LSM-Tree 的 SSTable

关键认知

  • 数据写入时 进入 Growing Segment(内存中),暂不建索引,以加速写入。
  • Growing Segment 达到阈值(默认 512MB)后封存Sealed Segment,异步构建索引。
  • Sealed Segment 不可变 ,只能在后台做 Compaction (合并小段)和 Index Rebuild(重建索引)。

这就是为什么 Milvus 写入后立即查询可能会比较慢------数据还在 Growing Segment 里走暴力扫描。生产环境通常会预热(force flush)或容忍短暂的查询不全。

2.4 索引原理:三种主流 ANN 索引

向量检索的核心是近似最近邻(Approximate Nearest Neighbor, ANN) 算法。Milvus 支持多种索引,我们重点看三类。

2.4.1 IVF(Inverted File)------ 基于聚类的倒排

三步法理解 IVF_FLAT:

step 1:聚类------用 K-Means 把所有向量聚成 nlist 个簇,每个簇有一个中心点。

step 2:分配------每个向量归属到距离最近的簇,记录"我属于哪个簇"。

step 3:检索------查询时先找最近的 nprobe 个簇,只在这些簇的向量里做精确距离计算,跳过其余向量。

复制代码
查询向量 → 计算到 nlist 个簇心的距离
        → 选最近的 nprobe 个簇(nprobe << nlist)
        → 只在这 nprobe 个簇里做精确 KNN

nlist 与 nprobe 是关键参数

  • nlist 越大 → 簇越多 → 单簇越小 → 检索越快,但召回率可能下降
  • nprobe 越大 → 扫描的簇越多 → 召回率越高,但延迟增加

HNSW 是当前最流行的图索引,可以理解为"向量世界的跳表"。

核心思想:构建一张多层图,每层的节点是向量的子集,层数越高节点越稀疏。查询时从最稀疏的顶层开始,每层贪心搜索找到局部最近点,然后下钻到下一层继续搜索。

复制代码
Layer 2: [A] ------------------------------ [Z]   ← 顶层:导航
Layer 1: [A] --- [M] --- [R] --- [Z]               ← 中层:粗定位
Layer 0: [A][B][C] ... [M][N][O] ... [Z]           ← 底层:精确搜索

优势 :查询速度极快(O(log N)),召回率高。

劣势:构建慢、内存占用大(需把图全装入内存)。

2.4.3 ANNOY ------ 基于树的分割

ANNOY 用多棵随机二叉树把空间切分,查询时在每棵树里找最近点后聚合。Milvus 已逐步弃用 ANNOY,实际生产推荐 HNSW 或 IVF。

2.5 一致性与隔离级别

Milvus 的"分布式"不是"主从复制"那么简单,它在写入可见性上提供四种一致性级别------这是面试常考点。

级别 含义 延迟 一致性
Strong 能读到最新写入
Session 同一会话内保证单调读
Bounded 容忍短暂延迟(默认)
Eventually 最终一致 极低 最弱

默认是 Bounded (bounded_staleness=5s),平衡了一致性与延迟。强一致必然牺牲性能------这与 CAP 定理一脉相承。


三、方案与对比

3.1 ChromaDB vs Milvus:何时升级

前面文章我们讨论了 ChromaDB 的轻量与易用。那么问题来了:什么时候必须升级到 Milvus? 让我们用一个对比表回答。

特性 ChromaDB Milvus
核心优势 简洁易用、开发速度快 高性能、高可扩展、功能丰富
架构 单体架构,可嵌入式运行 分布式架构,计算存储分离
数据规模 适合百万级向量 适合十亿级甚至万亿级向量
延迟(百万级) 毫秒级 毫秒级
延迟(十亿级) 不支持 / 性能崩溃 仍可保持毫秒~十毫秒级
适用场景 快速原型验证、中小项目、个人开发 企业级应用、大规模推荐系统、搜索引擎
部署复杂度 一行 pip install 即可 需 Docker Compose / K8s 部署多个组件
运维成本 几乎为零 需要运维 etcd / MinIO / Pulsar 等依赖
索引类型 默认 HNSW(固定) IVF / HNSW / PQ / DiskANN 等 10+ 种
多租户隔离 不支持 支持 Partition / Database 隔离
混合查询 标量过滤 + 向量检索 + 全文检索(2.4+)

选型有立场

  • 百万级以内、原型验证、学习阶段 → 选 ChromaDB:一行命令启动,5 分钟跑通 RAG。
  • 千万到亿级、追求功能丰富但不想自建 → 选 Zilliz Cloud(Milvus 云服务):免运维,按量付费。
  • 十亿级以上、金融级可靠性要求、有 K8s 团队 → 选 Milvus 自建集群:可控性最强。

为什么 ChromaDB 撑不住十亿级?因为它把向量全装进内存并用单进程做检索。十亿 768 维 float32 向量 ≈ 3TB 内存,单机物理极限就过不去。Milvus 用磁盘 + 内存分层 + 分布式,把"内存装不下"的问题转化成了"我可以横向扩"。

3.2 索引类型选型

确定用 Milvus 后,下一个关键决策是选哪种索引。这是性能调优的"第一颗扣子"。

索引类型 构建速度 查询速度 召回率 内存占用 适用场景
FLAT(暴力) 极快 100% 基线测试、<10w 向量
IVF_FLAT 95%+ 百万级、平衡场景
IVF_PQ 90%+ 低(压缩) 内存紧张、十亿级
HNSW 极快 98%+ 极高 低延迟、高召回场景
DISKANN 95%+ 极低 超大规模、SSD 充足

选型有立场

  • 追求极致召回率、不在乎内存 → 选 HNSW:M=16, efConstruction=200 是常用起点。
  • 内存有限、规模上亿 → 选 IVF_PQ:PQ 压缩能把内存降一个数量级。
  • 数据量超 10 亿 + SSD 充足 → 选 DISKANN:把索引放磁盘,内存只放热数据。

实际生产中召回率是底线 ------90% 召回率在 RAG 场景下意味着 10% 的查询会"找不到正确答案",这种损失往往是业务不可接受的。先用 FLAT 跑基线召回率,再压索引


四、实战步骤

下面我们一起从零跑通一个 Milvus 集群。虽然不能贴完整可运行项目(避免长代码淹没主线),但关键步骤和"踩过的坑"会一一标注。

4.1 step 1:部署模式选择

Milvus 提供三种部署模式,对应不同的场景:

模式 适用阶段 组件数 一句话
Milvus Lite 本地开发、学习 1 Python pip install milvus-lite,嵌入式
Standalone 中小规模生产 1 进程(含所有组件) Docker Compose 一键起
Cluster 大规模生产 多个微服务 K8s Helm Chart 部署

推荐路径:本地用 Lite 验证 → 小流量用 Standalone → 流量上量后切 Cluster。三者使用相同的 SDK,迁移成本几乎为零。

4.2 step 2:关键代码(Python SDK)

以下是连接 Milvus、创建 Collection、插入数据、检索的核心代码骨架。重点看注释里的"坑"

python 复制代码
from pymilvus import MilvusClient, DataType

# 1. 连接(注意:MilvusClient 是新版 SDK,旧版用 connections.connect())
client = MilvusClient(uri="http://localhost:19530")

# 2. 创建 Collection
schema = client.create_schema(
    auto_id=False,                          # 手动指定主键,便于幂等
    enable_dynamic_field=True               # 允许未定义的字段(调试期好用,生产建议关)
)
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=768)
schema.add_field(field_name="category", datatype=DataType.VARCHAR, max_length=64)

# 3. 配置索引(关键:metric_type 与算法强相关)
index_params = client.prepare_index_params()
index_params.add_index(
    field_name="vector",
    index_type="HNSW",                      # 索引类型
    metric_type="COSINE",                   # 距离度量:欧氏/内积/余弦
    params={"M": 16, "efConstruction": 200} # HNSW 参数
)

client.create_collection(
    collection_name="product_emb",
    schema=schema,
    index_params=index_params,
    consistency_level="Bounded"              # 默认级别,平衡性能与一致性
)

我们来逐段解读这段代码

  • enable_dynamic_field=True 允许插入"未在 schema 中定义"的字段。生产环境务必关闭------一旦打开,相当于把"字段约束"这一数据质量护栏拆了。
  • metric_type最容易踩坑 的地方:
    • 归一化后的 embedding(如 BGE、OpenAI)→ 用 IP(内积)或 COSINE(余弦)
    • 未归一化的特征向量 → 用 L2(欧氏距离)
    • 混用会导致召回率莫名其妙地低,而且代码不会报错。
  • consistency_level="Bounded" 是默认选项。如果你要做"插入后立即查询" (如 RAG 的实时数据入库),改用 Strong,否则可能查到旧数据。

4.3 step 3:插入与检索

python 复制代码
# 插入(注意:HNSW 不支持实时构建索引,数据会先进 Growing Segment)
data = [
    {"id": 1, "vector": [...], "category": "phone"},
    {"id": 2, "vector": [...], "category": "laptop"},
]
client.insert(collection_name="product_emb", data=data)

# 检索 + 标量过滤(混合查询是 Milvus 的杀手锏)
results = client.search(
    collection_name="product_emb",
    data=[query_vector],                    # 查询向量
    filter="category == 'phone'",           # 标量过滤
    limit=10,
    output_fields=["id", "category"],       # 返回字段
    search_params={"ef": 100}               # HNSW 检索参数
)

关键点解读

  • filter 参数支持类 SQL 表达式(==, in, >, and),这是 ChromaDB 做不到的。生产中"在某个分类下找相似商品"这类业务非常依赖它。
  • search_params={"ef": 100} 控制 HNSW 检索时的图遍历深度。ef 越大召回越高、延迟也越大 ,生产环境建议从 ef=64 起步压测。
  • 首次插入后立即 search 可能数据不全 ,因为 Growing Segment 还没被检索调度加载到 QueryNode。可用 client.flush() 强制封存(生产慎用,会卡写入)。

4.4 step 4:关键配置(生产避坑)

配置项 推荐值 含义 踩坑提醒
queryNode.replicas 2-3 查询节点副本数 副本越多查询并发越高,但内存翻倍
dataCoord.segment.maxSize 512MB Segment 封存阈值 太小会增加 Compaction 频率,太大会拖慢查询
queryNode.segcore.mmap.enable true(亿级以上) 启用 mmap 内存映射 节省内存,但首次查询会触发缺页中断
index.params.M 16 HNSW 每节点连接数 M 越大召回越高、内存越大
index.params.efConstruction 200 HNSW 构建时搜索深度 越大索引质量越好、构建越慢
quotaConfig.middle.*Protection.enabled true 内存/磁盘保护 防止 OOM 但会拒绝写入

提醒:以上参数都不是"越大越好" 。生产调优一定要带"召回率 + 延迟 + 内存"三维监控做 trade-off,单维压测会骗自己

4.5 step 5:验证手段

完成部署后,做三个最小验证:

  1. 健康检查curl http://<host>:9091/healthz 返回 200 → 组件就绪。
  2. 写入验证insert 一批数据 → query 主键能查到 → 通过。
  3. 召回率验证 :用 FLAT 索引(100% 召回)跑一遍测试集,记录 top-K 结果;再用 HNSW 跑同样的测试集,召回率 ≥ 95% 方可上线。

反直觉点:HNSW 索引参数在数据量翻倍后需要重新调优。M、efConstruction、ef 都不是"一调永逸"的参数。


五、总结

让我们把核心结论提炼成三条:

  1. Milvus 的本质是"分布式 + 存算分离 + 多索引可插拔"。理解了四层架构和三段式数据组织,排查任何问题都有据可循。
  2. ChromaDB 适合原型,Milvus 适合生产。当数据量从百万迈向十亿、QPS 从百迈向十万,Milvus 几乎是国内中大厂的"标准答案"。
  3. Milvus 不是"装上就能用" 。索引选型、一致性级别、参数调优、Compaction 策略共同决定生产表现。强烈建议先用 Milvus Lite 跑通,再上 Standalone,最后切 Cluster

适用边界

  • ✅ 适合:RAG 知识库、大规模推荐、图像/视频检索、广告投放、人脸识别
  • ⚠️ 谨慎:< 10w 向量的轻量场景(ChromaDB 更经济)
  • ❌ 不适合:纯事务型业务、需要强 JOIN 的关系查询(用 MySQL/PostgreSQL)

希望这篇文章能帮你从"知道 Milvus"走到"会用 Milvus"。下一篇文章,我们会一起动手搭建一个生产级的 Milvus + RAG 服务,把今天讲的架构、索引、参数调优全部串起来。


系列导航

向量数据库系列:从轻量到企业级,系统讲清选型与实战。

  • 第 1 篇:Milvus:为大规模、高性能而生的企业级向量数据库(本文)
  • 第 2 篇:待更新...

参考资料

相关推荐
骑士雄师1 小时前
18.2 PostgreSQL 的安装
数据库·postgresql
海南java第二人11 小时前
Nebula Graph 实战:基于图数据库存储 CMDB 实体关系
数据库·图数据库·nebula
曹牧11 小时前
oracle:“not all variables bound”
数据库·oracle
数据库百宝箱11 小时前
Oracle RMAN Image Copy 本地恢复
数据库·oracle
zuYM4g7Dp12 小时前
NoSql数据库设计心得
数据库·nosql
睡不醒男孩03082314 小时前
第七篇:揭秘 PostgreSQL 数据库内核级管控:CLup 深度架构设计与高可用底座技术白皮书
数据库·postgresql·clup
cmes_love15 小时前
Level 2逐笔成交历史数据下载方法笔记
数据库·笔记·oracle
swordbob15 小时前
MySQL字符集陷阱:从Oracle迁移踩坑到utf8mb4强制规范
数据库·sql
牛油果子哥q15 小时前
【C++ STL string 】C++ STL string 终极精讲:底层原理、内存机制、全套API、深浅拷贝、易错坑点与工程实战规范
数据库·c++