数据不搬家,也能做检索:Milvus的“湖原生”架构革命
——深度剖析Milvus的云原生架构、索引引擎与从2.x到3.0的存储范式跃迁
一句话概括:Milvus不是又一个向量数据库,而是一套以“存储与计算分离”为骨架、以“湖原生检索”为最新范式跃迁、以“分层微服务”为运行时的开源向量数据库操作系统——让百亿级向量检索从“先搬家再查询”的传统模式,变成“数据留在原地、索引就地构建”的零拷贝检索体系。
2019年,当Milvus在GitHub上第一次开源时,它解决的是一个很朴素的问题:如何在百万级向量上做快速的相似性搜索?
彼时,Faiss和HNSW已经在学术界证明了ANN(近似最近邻)搜索的可行性,但把它们包装成一个可扩展、可运维的数据库系统,仍然是空白。
六年后的2026年7月29日,Milvus 3.0正式发布。这一次,它要解决的问题变成了:当你的向量数据已经躺在数据湖里(Parquet、Lance、Iceberg),能不能不搬家就直接建索引、做检索?
看起来很简单,对吧?把向量往数据库里一插,就能搜了。
但是——当你的Embedding已经存在S3上的Parquet文件里,当你的数据治理要求“数据不能出湖”,当你的团队不想维护第二份在线数据副本,传统向量数据库的“先导入再检索”范式还够用吗?
Milvus 3.0给出的答案是:External Collections(外部集合)——直接在对象存储上的数据文件上构建索引,零拷贝、零迁移,让数据湖真正变得可检索。
本文将从架构演进、索引引擎、存储范式和工程实践四个维度,深度剖析Milvus的技术实现——它不是一次性的版本升级,而是一场从“向量数据库”到“向量数据湖基座(Vector Lakebase)”的范式革命。
一、整体架构与设计哲学:从“微服务”到“湖原生”
1.1 架构总览:四层分离,各司其职
Milvus的架构设计遵循“存储与计算分离、控制平面与数据平面分离、云原生弹性扩展”三大核心原则。整体架构自上而下分为四层:
┌─────────────────────────────────────────────────────────────┐ │ 接入层(Access Layer) │ │ Proxy节点(无状态网关、负载均衡) │ ├─────────────────────────────────────────────────────────────┤ │ 协调层(Coordinator Layer) │ │ RootCoord / DataCoord / QueryCoord / IndexCoord │ │ (集群大脑:拓扑管理、任务调度、一致性) │ ├─────────────────────────────────────────────────────────────┤ │ 执行层(Execution Layer) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │Streaming │ │ Query │ │ Data │ │ Index │ │ │ │ Node │ │ Node │ │ Node │ │ Node │ │ │ │(实时流) │ │(历史查询)│ │(写入持久化)│ │(索引构建)│ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ 存储层(Storage Layer) │ │ 元数据(etcd) + 日志(Pulsar/Kafka) + 对象存储(S3/MinIO)│ └─────────────────────────────────────────────────────────────┘接入层由一组无状态的Proxy节点组成,提供统一的API接口(Python/Java/Go/Node.js SDK及RESTful API),负责请求验证、负载均衡和结果聚合。
协调层是集群的“大脑”,包含RootCoord(元数据管理)、DataCoord(数据调度)、QueryCoord(查询调度)和IndexCoord(索引调度)四个协调器。集群中同一时刻仅有一个活跃的Coordinator节点(通过Raft协议实现主从切换)。
执行层是计算核心,包含三类工作节点:
- Data Node:负责数据插入、删除和持久化,将数据从内存缓冲区刷入对象存储
- Query Node:负责执行搜索和查询操作,从对象存储加载Segment到内存
- Index Node:负责为Sealed Segment构建索引
存储层由三部分组成:etcd存储元数据、Pulsar/Kafka作为消息队列(WAL)、S3/MinIO作为主要数据存储。
1.2 设计哲学的两次跃迁
第一次跃迁(2.x时代):存储与计算分离
Milvus 2.0重构为云原生架构,所有组件均为无状态组件。这种设计的核心收益在于:存储和计算可以独立扩展——数据量大了就扩存储节点,查询量大了就扩Query Node。
第二次跃迁(3.0时代):湖原生(Lake-Native)
Milvus 3.0最大的架构变革,是打破了“数据必须先导入向量数据库才能建立索引和提供检索”的传统范式。向量数据可以继续存放在对象存储上的开放格式(Parquet、Lance、Iceberg、Vortex)中,由Milvus负责就地构建索引、执行检索。
1.3 版本演进:从2019到2026
| 版本 | 发布时间 | 关键变化 |
|---|---|---|
| Milvus 1.0 | 2020年 | 首个开源版本,支持CPU/GPU向量检索 |
| Milvus 2.0 | 2021年 | 云原生重构,存储与计算分离,所有组件无状态化 |
| Milvus 2.3 | 2023年 | HNSW索引优化,C++实现工程级优化 |
| Milvus 2.4 | 2024年 | 高可用架构完善 |
| Milvus 2.5 | 2025年 | 内置BM25全文搜索,稀疏向量支持 |
| Milvus 2.6 | 2026年初 | AISAQ磁盘索引、RaBitQ、三层存储降本85% |
| Milvus 3.0 | 2026年7月29日 | 湖原生架构、External Collections、Loon存储引擎 |
数据来源:Milvus官方发布说明及GitHub Releases
二、核心抽象与数据模型:Collection、Segment与Chunk
2.1 数据模型的三层抽象
Milvus的数据模型采用三层抽象:
| 层级 | 概念 | 说明 |
|---|---|---|
| Collection | 集合 | 类似于关系型数据库中的“表”,是数据的逻辑组织单元 |
| Partition | 分区 | Collection内的数据分区,支持按时间等维度划分 |
| Segment | 段 | 数据存储的最小物理单元,分为Growing Segment和Sealed Segment |
2.2 Segment的生命周期:从“Growing”到“Sealed”
一个Milvus数据单元的完整旅程:
用户插入数据 → Proxy → 消息队列(Pulsar/Kafka) ↓ Data Node消费消息 → 写入Growing Segment(内存缓冲区) ↓ Segment达到阈值(默认122MB)→ Sealed(封存) ↓ Data Node将Chunk刷入对象存储(S3/MinIO) ↓ Index Node加载Segment → 构建索引 → 索引文件存回对象存储 ↓ Query Node加载索引 → 提供查询服务逐层解读:
① Proxy与消息队列:用户通过SDK发送插入请求到Proxy节点。Proxy对主键做哈希,决定发送到哪个Channel(Pulsar或Kafka Topic)。
② Growing Segment:Data Node从Channel消费数据,写入内存缓冲区——这就是Growing Segment。每个Shard只有一个Growing Segment。
③ Chunk与持久化:Segment增长过程中,每达到16MB就形成一个Chunk,推送到对象存储。每个Chunk是对象存储上的一个物理文件,每个字段有独立的文件。
④ Sealing与合并:当Segment达到122MB时被Sealed。Data Node定期将小的Sealed Segment合并成更大的Segment,最大可达1GB。
⑤ 索引构建:Index Node从对象存储加载Sealed Segment的数据,构建索引(如IVF、HNSW),然后将索引文件存回对象存储。
⑥ 查询服务:Query Node按QueryCoord调度,从对象存储加载Segment数据(向量、标量、索引文件)到内存或本地SSD缓存。
设计权衡(Segment大小):
该设计的收益在于:① 通过分片(Shard)和分段(Segment)充分压榨集群的并行计算能力;② Growing Segment保证“写入后立即可查”;③ Sealed Segment的不可变性简化了索引管理和并发控制。
该设计的代价在于:① 小Segment过多会影响查询性能(召回率下降);② 需要后台Compaction任务持续合并小Segment。
2.3 流批分离:Streaming Node的诞生
在经典架构中,Query Node既处理Sealed数据(历史、高吞吐),又处理Growing数据(实时、低延迟)——一个节点干了两种性质完全不同的活。
最新架构中,新增了Streaming Node,专职处理尚未Flush的Growing Segment数据:
- 提供刚写入数据的实时搜索能力
- 为搜索请求生成查询计划
- 当Growing Segment达到阈值时,触发转换为Sealed Segment
同时,Index Node合并进Data Node——索引构建和Compaction都是离线批处理任务,放在同一节点可避免不必要的数据传输。
三、核心模块源码解析:索引引擎与查询执行
3.1 索引体系:从内存到磁盘的全覆盖
Milvus支持多种索引类型,覆盖不同的性能/内存/精度权衡:
| 索引类型 | 原理 | 适用场景 |
|---|---|---|
| FLAT | 暴力扫描 | 数据量小(<10万),追求100%召回率 |
| IVF_FLAT | 倒排索引+聚类 | 平衡性能与精度,通用场景 |
| IVF_SQ8 | IVF + 标量量化 | 内存受限场景 |
| IVF_PQ | IVF + 乘积量化 | 极致压缩,超大数据集 |
| HNSW | 分层可导航小世界图 | 高QPS,内存充足 |
| DISKANN | 基于磁盘的ANN | 百亿级数据,内存极度受限 |
| GPU_CAGRA | GPU加速图索引 | GPU集群,追求极致吞吐 |
| AISAQ | 基于SSD的磁盘索引 | 十亿级数据,内存压缩3200倍 |
| RaBitQ | 1-bit量化 | 内存压缩至1/32,QPS提升4倍 |
HNSW的工程实现:Milvus 2.3版本对HNSW索引进行了C++层面的工程级优化。在鲲鹏服务器上,经过预取优化后,HNSW算法在0.99精度下不同并发的查询效率均有40%+的提升。
DISKANN与AISAQ:DISKANN通过将索引放到SSD上减少内存压力。Milvus 2.6进一步引入AISAQ(由铠侠KIOXIA开发),一种受DISKANN启发的基于磁盘的向量索引。AISAQ能将十亿级搜索的内存占用压缩3200倍。
RaBitQ:从Milvus 2.6开始支持,采用1-bit量化,将主索引压缩至原内存的1/32,叠加SQ8精排后整体内存占比仅28%,QPS提升4倍,召回率保持95%左右。
设计权衡(索引选择):
该设计的收益在于:丰富的索引类型让用户可以根据数据规模、硬件配置和性能要求灵活选择。
该设计的代价在于:索引选型复杂——不同索引的参数(nlist、M、efConstruction等)需要针对具体场景调优。
3.2 查询执行流程:从Proxy到Segcore
一次搜索请求在Milvus中的完整执行路径:
客户端(Python/Java/Go SDK)→ gRPC/REST请求 ↓ 【Proxy】请求验证 → 生成查询计划 → 分发到各Query Node ↓ 【Query Node】ShardDelegator协调 → 并行执行 ├── Growing Segment(Streaming Node处理) └── Sealed Segment(Query Node从缓存/对象存储加载) ↓ 【Segcore(C++核心引擎)】执行查询计划 ├── 标量过滤(Visitor模式遍历表达式树) ├── 向量检索(ANN索引搜索) └── 结果合并与TopK排序 ↓ 【Proxy】聚合各节点结果 → 返回客户端Segcore的执行机制:Milvus使用Visitor模式在Segment上执行查询计划。底层通过milvus::exec::Task管理查询的生命周期。查询执行涉及创建QueryContext来持有Segment元数据和查询参数。
标量过滤的优化:Milvus采用列式向量化的方式执行标量过滤表达式——一次处理一批数据,而非逐行处理。
3.3 索引引擎拆解:三层填充与16倍内存取舍
Milvus的索引引擎在设计上做了精妙的内存取舍:
- 三层填充策略:索引构建过程中,通过三层填充优化内存使用和构建速度
- 编译期分流:将不同索引类型的逻辑在编译期分离,避免运行时分支开销
- 16倍内存取舍:在索引构建速度和内存占用之间做了明确的权衡——用更多内存换取更快的构建速度,或将内存压到极致但接受更长的构建时间
四、核心执行流程与运行时机制
4.1 写入链路:从内存到对象存储的完整旅程
Insert请求 → Proxy(主键哈希)→ Pulsar/Kafka(WAL) ↓ Data Node消费 → Growing Segment(内存缓冲) ↓(每16MB) Chunk → 对象存储(S3/MinIO) ↓(达到122MB) Seal Segment → 元数据更新(etcd) ↓ Index Node → 加载Segment → 构建索引 → 索引文件存入对象存储 ↓ Query Node → 加载索引 → 提供服务你可能会担心:Data Node还没刷盘时节点宕机了怎么办?
别担心,WAL(Write-Ahead Log)机制保证了数据安全。所有插入请求先写入Pulsar/Kafka,Data Node从日志中消费并写入Growing Segment。即使Data Node宕机,数据仍在消息队列中,重启后可继续消费。
4.2 查询链路:Growing与Sealed的协同
查询请求到达后,ShardDelegator负责协调:
- Growing数据:由Streaming Node处理,保证“写入后立即可查”
- Sealed数据:由Query Node从缓存或对象存储加载
两种数据源的结果在Query Node层合并,统一返回给客户端。
4.3 一致性模型:时间戳与MVCC
Milvus通过TSO(Timestamp Oracle)分配全局唯一时间戳,保证事务一致性。查询时,系统基于时间戳读取特定版本的数据——类似数据库的MVCC机制。
时间旅行(Time Travel):用户可以通过指定时间戳,查询历史某个时刻的数据状态。
五、存储引擎的范式革命:从2.x到3.0
5.1 2.x时代:散落的Binlog
在Milvus 2.x中,存储模型是逐binlog文件的方式——每个Segment的每个字段对应多个binlog文件,散落在对象存储中。
这种模型的问题在于:
- 元数据膨胀:每个binlog都需要在etcd中记录元数据
- 读取放大:查询一个Segment需要打开大量小文件
- Schema演进困难:增加或删除字段需要重建整个Collection
5.2 3.0时代:Manifest表 + Loon存储引擎
Milvus 3.0的存储层经历了一次范式级别的重写——从逐binlog文件模型,转向了类似Apache Iceberg的manifest表格式。
新的存储引擎名为Loon,核心设计围绕三个要素展开:
- 混合文件格式:将向量数据、标量数据和索引组织在统一的文件格式中
- 行ID对齐:保证向量和标量在物理存储上的对齐,加速混合查询
- Manifest:定义数据集的版本化状态,支持Schema演进和时间旅行
Loon的收益:
- 降低读取放大:随机点查不再需要打开大量小文件
- 支持Schema演进:在线添加、回填和删除列成为可能
- 零拷贝外部数据访问:External Collection直接读取湖上数据
5.3 External Collections:数据不搬家,也能建索引
External Collection是Milvus 3.0最核心的新功能:
# 直接在S3上的Parquet文件上定义Collectionclient.create_collection(collection_name="external_vectors",# 外部数据源:S3上的Parquet文件external_source={"format":"parquet","location":"s3://my-bucket/embeddings/"},schema=schema)# 然后就像普通Collection一样使用client.search(collection_name="external_vectors",...)核心机制:
- 零拷贝:数据文件不移动,Milvus直接读取对象存储上的文件
- 就地索引:在外部数据上直接构建向量索引、BM25倒排索引、JSON索引和标量索引
- 增量更新:当外部数据集更新后,Milvus读取对应的Storage Manifest,仅对新数据分片构建索引
- 只读:External Collections是只读的,适合治理要求“数据不能出湖”的场景
六、工程化实践:从部署到生产
6.1 部署模式与资源规划
Milvus支持两种部署模式:
| 模式 | 适用场景 | 组件 |
|---|---|---|
| Standalone | 开发测试、小规模生产 | 单进程包含所有功能 |
| Distributed | 大规模生产、高并发 | 各组件独立部署,可横向扩展 |
核心依赖:
- 元数据存储:etcd
- 消息队列:Pulsar或Kafka(作为WAL)
- 对象存储:MinIO、AWS S3、GCS、Azure Blob等
Woodpecker:Milvus 3.0引入的原生WAL服务,借鉴BookKeeper的分布式日志模型,同时结合对象存储和云网络特性进行了重新设计。在跨可用区部署、对象存储利用和成本控制方面进一步优化,性能比传统Kafka方案快5.8倍。
6.2 性能优化策略
① 索引选型优化
| 数据规模 | 推荐索引 | 参数建议 |
|---|---|---|
| < 100万 | HNSW | M=16, efConstruction=200 |
| 100万–1000万 | IVF_FLAT | nlist=4096, nprobe=16 |
| 1000万–1亿 | IVF_SQ8 / IVF_PQ | nlist=16384, 根据精度需求 |
| > 1亿 | DISKANN / AISAQ / RaBitQ | 根据硬件配置 |
② 分段大小调优
默认Segment大小为122MB,合并后最大1GB。小Segment数量过多会影响查询性能——Compaction后台任务会持续合并小Segment、清理删除数据。
③ 缓存策略
Query Node从对象存储加载Segment到内存或本地SSD缓存。合理配置缓存大小可以显著降低查询延迟。
④ 资源隔离
通过PartitionKey隔离,可在同一Collection中实现不同业务的数据隔离,提升性能。
6.3 调试与可观测性
Milvus提供了多层次的观测能力:
- Attu:官方GUI管理工具,可视化查看Collection、Segment状态
- Metrics:通过Prometheus暴露各项性能指标
- 日志:各组件独立日志,支持日志级别动态调整
6.4 常见工程陷阱与解决方案
陷阱1:小Segment爆炸
大量小Segment会导致查询时打开过多文件,召回率下降。
解决方案:调整Data Node的合并策略,定期执行Compaction。生产环境建议监控Segment数量,设置合理的合并阈值。
陷阱2:索引构建资源竞争
Index Node构建索引时会消耗大量CPU和内存,可能影响查询性能。
解决方案:在Distributed部署中,将Index Node独立部署,与Query Node隔离资源。
陷阱3:消息队列积压
Pulsar/Kafka消费速度跟不上写入速度时,会导致Growing Segment积压。
解决方案:监控消息队列的Lag,适当增加Data Node数量或调整Segment刷盘阈值。
七、总结与展望
7.1 关键版本里程碑
| 时间 | 版本 | 意义 |
|---|---|---|
| 2019年 | Milvus开源 | 首个开源向量数据库项目 |
| 2021年 | Milvus 2.0 | 云原生重构,存储与计算分离 |
| 2025年 | Milvus 2.5 | 内置BM25全文搜索,混合检索成为标配 |
| 2026年初 | Milvus 2.6 | AISAQ磁盘索引、RaBitQ、三层存储降本85% |
| 2026年7月29日 | Milvus 3.0 | 湖原生架构、External Collections、Loon存储引擎 |
7.2 核心设计哲学提炼
Milvus的演进可以用三句话概括:
“存储与计算分离是地基,不是选项”——从2.0开始,Milvus就将无状态化作为架构的基石,让存储和计算可以独立扩展
“索引不是终点,检索才是”——从FLAT到HNSW到DISKANN到AISAQ到RaBitQ,每一次索引创新都在追问同一个问题:“如何在更少的硬件上做更快的检索?”
“数据在哪,检索就该在哪”——Milvus 3.0的湖原生架构,把“数据不搬家也能建索引”从理想变成了现实
7.3 核心架构亮点速览
| 亮点 | 说明 | 效果 |
|---|---|---|
| 四层分离架构 | 接入/协调/执行/存储四层独立 | 各层可独立扩展,高可用 |
| 流批分离 | Streaming Node专职处理实时数据 | 写入后立即可查,延迟稳定 |
| 索引全覆盖 | 从内存到磁盘、从CPU到GPU | 覆盖从百万到百亿级所有场景 |
| RaBitQ量化 | 1-bit量化压缩至1/32 | QPS提升4倍,召回率95% |
| Loon存储引擎 | Manifest表格式+混合文件 | Schema演进、零拷贝外部访问 |
| External Collection | 数据湖就地建索引 | 无需第二份副本,零拷贝检索 |
7.4 对开发者的启示
Milvus的故事告诉我们:向量数据库的竞争,正在从“谁更快”变成“谁更省”和“谁更灵活”。
2019年,大家关心的是“百万级向量能不能搜”。2023年,大家关心的是“十亿级向量能不能搜”。2026年,问题变成了“数据已经在湖里了,能不能不搬家就搜?”
这种“优化跑步机”不会停止。随着AI应用从“演示级”走向“生产级”,数据规模从百万走向百亿,向量数据库的架构必须持续演进。
对于开发者,这意味着:
- 选型时关注架构演进方向——云原生是底线,湖原生是趋势
- 部署时关注存储成本——对象存储比本地盘便宜一个数量级,能走S3就走S3
- 索引选型要结合数据规模——百万级和亿级的索引策略完全不同
- 关注3.0的External Collections——如果你的数据已经在数据湖里,这可能是最优解
最后,Milvus从2019年的一个向量检索工具,到2026年的湖原生向量数据湖基座——六年时间,它不仅回答了“怎么搜得快”,更在回答“怎么搜得省、搜得灵活”。而答案,正写在每一行开源代码和每一次架构重构里。
本文数据来源:Milvus官方文档(milvus.io)、GitHub Releases(github.com/milvus-io/milvus)、Milvus官方博客(blog.milvus.io)、DeepWiki及社区技术文章。所有版本号、功能特性及性能数据均基于公开可验证的官方资料。
如您所在的企业正面临向量检索、RAG系统构建或AI数据基础设施的相关需求,欢迎进一步沟通。我们可提供针对贵企业具体场景的定制化方案和现场调研服务。