Milvus 3.0 开源解读之Manifest|AI 数据管理,应该彻底放弃文件中心架构
在 AI 时代,同一份数据同时服务于向量检索、批量计算、实时分析与模型训练评估,已成为现代数据架构的常态。然而,大部分企业依然在用上一代思维应对新时代的诉求:通过在不同计算引擎间不断复制数据,来换取各自的执行效率。
数据不断复制的终点,是存储成本的无限膨胀与数据状态的彻底失控。最终导致删除与修正无法同步,每次数据更新都演化为灾难性的全量迁移,“哪一个才是当前真实的数据集”这个最简单的问题,竟成了系统架构中最难回答的终极之问。
那么,能不能数据原格式留在原地,让不同的计算引擎围绕同一个数据版本高效协同?
这也是我们在Milvus 3.0 重新设计存储底层的出发点。
在 Storage V3 中,我们通过提供数据集的元数据清单(即Manifest,借用自Iceberg,后文统一使用Manifest表达 ),将数据的物理存储与数据集版本管理彻底解耦。
从此,传统数据库/数据湖在向量场景下经常会出现的由于拷贝多份数据造成的读写放大、多源不一致,被一并根治。这也使得它在保持在线低延迟检索的同时,让离线大数据分析与外部训练引擎的零拷贝协作成为现实。
传统模式:数据复制 ➔ 副本分散 ➔ 状态失控 ➔ 成本线性暴涨 Storage V3:数据原地 ➔ Manifest 统一表达 ➔ 跨引擎零拷贝共享
在本文,我们将重点解读其中的 Manifest能力, 作为一个数据集版本的权威描述,Manifest可以说明当前版本由哪些数据与文件组成、这些数据位于哪里、需要应用哪些删除信息、哪些统计信息和索引属于这个版本,把存储系统的管理中心从文件管理时代,提升到了数据集版本管理时代。
为什么需要Manifest ?传统文件管理无法支持多系统共同操作一份数据
最早期的数据管理,主要服务于在线检索,系统设计也通常以文件为中心。只要数据文件、删除日志和索引文件得到正确保存,系统就能运转。
但问题在于,文件只能表达局部事实,并不自动构成一个完整的数据集状态。
一个parquet文件可以表示有哪些数据,是什么数据类型,却不能单独回答:这些文件属于哪个版本?哪些删除记录对应哪些数据文件?哪些统计信息仍然有效?哪些索引因为数据变化已经失效?当前系统到底该以哪一组文件为准?
过去,这些关系通常隐藏在Milvus 内部的文件命名和模块之间的代码约定中。但随着并发写入、Compaction、恢复、外部数据刷新和多格式支持不断加入,隐式关系会迅速变成架构负担。
因此,在Storage V3 ,我们引入了统一的Manifest ,作为一个数据集版本的完整描述,它将原本分散在数据文件、删除日志、统计信息和索引文件中的关系,收拢为一个可以被统一读取和管理的版本化对象。
一份 Manifest 可以描述:
- 当前版本采用的 Schema;
- 该版本包含哪些数据文件;
- 文件位于哪些存储位置;
- 需要应用哪些删除信息;
- 哪些统计信息与当前版本对应。
当数据集发生变化时,系统不再零散地修改一组当前文件,而是生成一个能够描述新状态的 Manifest。旧版本仍然保留,新版本则成为下一轮查询、加载和刷新所依据的数据集快照。
这一层抽象带来了三个收益。
1.数据集状态第一次有了稳定快照。 数据集的当前状态不再是分散于文件、日志与索引中的隐式关系,而是被显式收录为不可变的版本化对象。系统只需读取对应版本的 Manifest,就能够知道这一时刻的数据应该如何被解释。
2. 并发更新有了统一协调点。 多路写入与更新发生时,系统不再散落修改文件,而是围绕同一个 Manifest 进行原子提交、冲突仲裁与新版本生成。
3.上层感知解耦,不必理解过多文件细节:查询、压缩、恢复与外部刷新等上层组件,无需再去关注文件、删除记录、统计信息、索引间的交织关系。它们只需对接 Manifest ,Manifest 怎么定义,数据集此刻就被如何读取与理解。
(注:当前版本Mmanifest主要针对的是segment,不是整个collection;完整的table format已在roadmap规划中。)
借助Manifest ,系统如何避免碎片化格式入侵上层组件
过去,一个系统中,如果需要读写parquet/lance/vortex,需要Milvus理解这些格式侵入代码逻辑。于是,每一个上层模块,都要针对不同格式,做一套处理链路。
但在 Storage V3 提供抽象后,上层组件不必关心某个文件到底是 Parquet、Vortex 还是别的格式,只需要知道:这份外部数据是什么;它属于哪个数据集。这个也是storage v3内部的逻辑,Milvus只要调用FFI接口就可以直接在抽象层次处理 写入/读取/增删列等操作。
当然,不同格式有自己的物理差异,比如探索方式、列映射方式、底层读取方式都可能不同,我们也必须承认不同格式有不同的物理特征,某些外部源也会带来额外的映射规则。
但只要进入了 Manifest 层,它们就都变成了同一类对象:可被 Milvus 管理的数据集片段。
对 Parquet、Vortex、Iceberg 这类外部格式来说,接入路径可以概括为几步:
- 识别外部数据源;
- 理解其文件边界与数据范围;
- 将这些文件组织成目标数据集的一部分;
- 让后续查询、加载、刷新都围绕同一套数据集语义工作。
这件事可以概括成一句话:Storage V3 把“若干外部文件”翻译成了“一个 Milvus 可以管理的数据集片段”。这样一来,后续的查询、加载、刷新、甚至恢复,都可以围绕同一个数据集语义工作。格式差异被限制在了最靠近存储的一层,不会扩散到整条数据链路。
借助Manifest ,不同外表的数据如何进入 Milvus 生命周期
在 Milvus 3.0 中,我们推出了External Collection 。借助它,你可以直接在 Milvus 中直接链接对象存储上的数据集,将外部字段映射到 Milvus Schema,无需移动数据文件,Milvus就会在原地直接构建向量索引、BM25 倒排索引、JSON 索引以及标量索引。
当然,接入外部数据的核心壁垒,从来不是“如何打开一个 Parquet 文件”,而是如何将外部数据无缝融入数据库的严格语义中(包括 Schema 映射、删除语义、索引有效性与恢复一致性)。
Manifest 正是完成这层转换的关键。
外部文件或外部表
│
│ 识别 Schema、文件和数据范围
▼
转换为统一的数据集描述
│
│ 生成或引用 Manifest
▼
进入 Milvus 的查询、加载、刷新和索引生命周期
完成 Manifest 化之后,外部数据就不再是一条独立旁路。而是变成一个 Milvus 可以长期管理的数据集对象,进入了 Milvus 的数据集生命周期。
让另一个milvus 实例中的milvus collection(aka milvus-table)作为外表的数据源
如果说普通 external format 展示的是“如何把文件变成 Manifest”,那么 milvus-table 展示的就是更高级的一层能力:把一个数据集定义,翻译成另一个数据集定义。milvus-table 的 external source 不是普通文件目录,而是一份 Milvus 快照。该快照已经包含集合结构、数据组织方式、删除信息以及统计和辅助元数据等数据集语义。
这和 Parquet 外表完全不是一个复杂度级别。接入普通文件时,系统需要从文件中识别并建立数据集关系;接入 milvus-table 时,系统已经帮你理解了已有的数据集定义,并把它转换成目标集合可管理的数据集状态,这也是零拷贝主路径能够成立的关键。
过去,接入外部数据,通常需要对数据做一次全量重写,但如果系统已经拥有 Manifest 这层抽象,那么它就可以选择另一条路径:
- 保留 source 数据文件;
- 翻译 source Manifest 的结构关系;
- 只为目标系统补写必要的增量内容。
这种重写元数据关系代替全量数据重写的模式,改变了跨系统协作的成本模型:使大规模数据的接入成本彻底脱离了数据量本身的线性束缚,也让跨系统共享同一份底层数据变得更现实。
基于Manifest 的Refresh ,让周期性暴力全量重导入简化为版本演化
外部数据是动态流转的,物理文件、删除记录与 Schema 随时可能变化。在文件级管理视角下,数据 Refresh 往往意味着重新扫描目录、比对文件、然后重新全量导入。
Manifest 将 Refresh 的判断单位提升到了数据集版本层面:
判断底层数据主体是否真正发生变化
├── 仅增量信息变化 ➔ 重写 Manifest 元数据关系(最小代价演进)
└── 数据主体失效 ➔ 重新构建版本快照
如果当前数据集版本的主体依然成立,系统就无需重拉数据,只需以极小代价重写 Manifest。这种将重新导入简化为版本演化的思路,才是现代化数据库元数据管理的精髓所在。
结语
回过头看,Storage V3 的真正价值,在于让 Milvus 彻底完成了从“围绕文件组织流程”到“围绕数据集版本组织系统”的抽象升级。
这一底座赋予了Milvus 3.0三重维度的全新能力:
- 对内,它统一写入、加载、查询、恢复语义;Spark、Ray等外部数据不再通过一条独立旁路被临时读取,可以借助 Manifest 正式进入 Milvus 生命周期。
- 对外,它可以成为跨系统共享的数据入口: 对于普通外部格式,这个底座负责把文件组织成一份包含版本、Schema、删除信息和文件关系的完整数据集快照的数据集;对于 milvus-table,它负责把一个已有数据集翻译为另一个数据集;对于更广义的跨系统数据协同,它则提供了一个可共享、可迁移、可重定位、可演进的数据集定义方式。
- 对下,它让不同物理格式可以被统一纳管。 Parquet、Vortex、Iceberg 等格式仍然保留各自的存储与读取特征,但屏蔽了其差异性,避免格式碎片化污染上层计算链路。
当然,这种高度的表达力并非没有代价。
它要求系统对版本生命周期、并发一致性拥有极其严密的掌控力,也要求上层机制在享受零拷贝红利的同时,精准处理派生数据与删除语义的增量生成。
可控的代价,换来的是极致的表达力与掌控力。 这不仅是 Milvus 存储底层的进化,更为 AI 时代跨系统的数据协同,提供了一个稳定、从容且具备长久生命力的底层基础设施。






