停止为冷数据付费:Milvus 分层存储中的按需冷热数据加载可降低 80% 的成本
有多少人还在为系统几乎不接触的数据支付高级基础设施费用?说实话,大多数团队都是这样。
如果你在生产中运行向量搜索,你可能已经亲眼目睹了这种情况。你需要配置大量内存和固态硬盘,以便一切都能 "随时查询",尽管实际上只有一小部分数据集处于活动状态。你并不孤单。我们也见过很多类似的情况:
多租户 SaaS 平台:数以百计的入驻租户,但每天只有 10-15% 的租户处于活跃状态。其余的租户处于闲置状态,但仍占用资源。
电子商务推荐系统:一百万个 SKU,但前 8%的产品产生了大部分推荐和搜索流量。
人工智能搜索:庞大的 Embeddings 档案,尽管 90% 的用户查询都是搜索过去一周的商品。
各行各业的情况都一样:只有不到 10% 的数据被频繁查询,但却往往消耗了 80% 的存储空间和内存。每个人都知道这种不平衡的存在,但直到最近,还没有一种简洁的架构方法来解决这个问题。
Milvus 2.6 的发布改变了这一状况。
在此版本发布之前,Milvus(与大多数向量数据库一样)依赖于满载模型:如果需要搜索数据,就必须将其加载到本地节点上。不管数据是每分钟上千次还是每季度一次,都必须保持热状态。这种设计选择确保了可预测的性能,但同时也意味着集群规模过大,需要为冷数据支付根本不值得的资源费用。
分层存储 就是我们的答案。
Milvus 2.6 引入了全新的分层存储架构,真正实现了按需加载,让系统自动区分热数据和冷数据:
热数据段缓存在靠近计算的地方
冷数据段在远程对象存储中廉价运行
只有在查询实际需要时,才将数据调入本地节点
这就将成本结构从 "拥有多少数据 "转变为"实际使用多少数据"。在早期的生产部署中,这种简单的转变最多可降低 80% 的存储和内存成本。
在本篇文章的其余部分,我们将介绍分层存储的工作原理,分享实际的性能结果,并说明这一变化在哪些方面产生了最大的影响。
为什么全加载会在规模上崩溃
在深入探讨解决方案之前,我们不妨仔细研究一下 Milvus 2.5 和早期版本中使用的满载模式为何会在工作负载扩展时成为限制因素。
在 Milvus 2.5 及更早版本中,当用户发出Collection.load() 请求时,每个 QueryNode 都会在本地缓存整个 Collections,包括元数据、字段数据和索引。这些组件从对象存储中下载并存储在内存中或内存映射(mmap)到本地磁盘中。只有当所有这些数据都在本地可用后,Collection 才会被标记为已加载并可为查询提供服务。
换句话说,在节点上出现完整数据集(热数据集或冷数据集)之前,该 Collections 是不可查询的。
注意:对于嵌入原始向量数据的索引类型,Milvus 只加载索引文件,而不单独加载向量字段。即便如此,无论实际访问了多少数据,都必须完全加载索引才能为查询提供服务。
要了解为什么会出现这种问题,请看一个具体的例子:
假设你有一个中等规模的向量数据集,其中有
1 亿向量
768 个维度(BERT Embeddings)
float32精度(每个维度 4 字节)
一个HNSW 索引
在此设置中,仅 HNSW 索引(包括嵌入的原始向量)就占用了约 430 GB 的内存。在添加用户 ID、时间戳或类别标签等常用标量字段后,本地资源总使用量轻松超过 500 GB。
这意味着,即使 80% 的数据很少被查询或从未被查询过,系统仍必须提供并持有超过 500 GB 的本地内存或磁盘,才能保持 Collections 在线。
对于某些工作负载,这种行为是可以接受的:
如果几乎所有的数据都被频繁访问,那么完全加载所有数据就能以最高的成本实现最低的查询延迟。
如果数据可以分为热子集和热子集,那么将热数据内存映射到磁盘可以部分减轻内存压力。
但是,在 80% 或更多数据位于长尾数据的工作负载中,完全加载的缺点很快就会显现出来,包括性能和成本两方面。
性能瓶颈
在实际操作中,全加载影响的不仅仅是查询性能,往往还会拖慢常规操作符的工作流程:
滚动升级时间更长:在大型集群中,滚动升级可能需要数小时甚至一整天的时间,因为每个节点都必须重新加载整个数据集,然后才能再次可用。
故障后恢复较慢:查询节点重启后,在重新加载所有数据之前无法提供流量服务,这大大延长了恢复时间,并扩大了节点故障的影响。
迭代和实验速度减慢:完全加载会减慢开发工作流程,迫使人工智能团队在测试新数据集或索引配置时等待数小时才能加载数据。
成本效率低下
全加载还会推高基础设施成本。例如,在主流云内存优化实例上,本地存储 1 TB 数据的成本约为
现在考虑一种更现实的访问模式,其中 80% 的数据是冷数据,可以存储在对象存储中(大约 0.023 美元/GB/月):
200 GB 热数据 × 5.68 美元
800 GB 冷数据 × 0.023 美元
年成本:(200×5.68+800×0.023)×12≈14,000美元
总存储成本降低了 80%,而性能却没有受到影响。
分层存储是什么,如何工作?
为了消除权衡,Milvus 2.6 引入了分层存储,它将本地存储视为缓存,而不是整个数据集的容器,从而平衡了性能和成本。
在这种模型中,查询节点在启动时只加载轻量级元数据。字段数据和索引会在查询需要时按需从远程对象存储中获取,如果需要频繁访问,则会在本地缓存。不活动的数据可以被驱逐,以释放空间。
因此,热数据留在靠近计算层的地方,以便进行低延迟查询,而冷数据则留在对象存储中,直到需要时再取出。这就缩短了加载时间,提高了资源效率,并允许查询节点查询远大于本地内存或磁盘容量的数据集。
在实际应用中,分层存储的工作原理如下:
将热门数据保留在本地:大约 20% 的频繁访问数据保留在本地节点上,确保最重要的 80% 查询的低延迟。
按需加载冷数据:剩下的 80% 很少访问的数据只在需要时才获取,从而释放了大部分本地内存和磁盘资源。
利用基于 LRU 的驱逐功能进行动态调整:Milvus 采用 LRU(最近最少使用)驱逐策略,不断调整哪些数据被视为热数据或冷数据。不活动的数据会被自动驱逐,为新访问的数据腾出空间。
通过这种设计,Milvus 不再受限于本地内存和磁盘的固定容量。取而代之的是,本地资源作为动态管理的缓存,不断从非活动数据中回收空间,并重新分配给活动工作负载。
这种行为由三个核心技术机制实现:
1.懒加载
在初始化时,Milvus 只加载最小的分段级元数据,使 Collections 在启动后几乎立即就可以进行查询。字段数据和索引文件保留在远程存储中,在执行查询时按需获取,从而保持较低的本地内存和磁盘使用率。
Collections 加载在 Milvus 2.5 中的工作原理
在 Milvus 2.6 及更高版本中,懒加载是如何工作的
初始化过程中加载的元数据主要分为四类:
段统计信息(基本信息,如行计数、段大小和 Schema 元数据)
时间戳(用于支持时间旅行查询)
插入和删除记录(在查询执行过程中需要保持数据一致性)
Bloom 过滤器(用于快速预过滤,以快速消除不相关的数据段)
2.部分加载
懒加载控制数据加载的时间,而部分加载控制数据加载的数量。一旦开始查询或搜索,查询节点就会执行部分加载,只从对象存储中获取所需的数据块或索引文件。
向量索引:租户感知加载
Milvus 2.6+ 引入的最有影响力的功能之一是向量索引的租户感知加载,这是专门为多租户工作负载设计的。
当查询访问单个租户的数据时,Milvus 只加载向量索引中属于该租户的部分,而跳过所有其他租户的索引数据。这就使本地资源集中在活跃租户上。
这种设计有几个好处:
不活动租户的向量索引不占用本地内存或磁盘
活动租户的索引数据保持缓存状态,以实现低延迟访问
租户级 LRU 驱逐策略可确保各租户公平使用缓存
标量字段列级部分加载
部分加载也适用于标量字段,允许 Milvus 仅加载查询明确引用的列。
考虑一个有50 个 Schema 字段的 Collections,如id,vector,title,description,category,price,stock, 和tags ,您只需要返回三个字段--id,title, 和price 。
在Milvus 2.5 中,无论查询要求如何,都会加载所有 50 个标量字段。
在Milvus 2.6+ 中,只加载所要求的三个字段。其余 47 个字段保持未加载状态,只有在以后需要访问时才会懒散地获取。
这样可以节省大量资源。如果每个标量字段占用 20 GB:
加载所有字段需要1,000 GB(50 × 20 GB)
只加载三个所需字段需要60 GB
这意味着标量数据加载量减少了 94%,而不会影响查询的正确性或结果。
注:针对标量字段和向量索引的租户感知部分加载将在即将发布的版本中正式推出。一旦推出,它将进一步减少负载延迟,提高大型多租户部署中的冷查询性能。
3.基于 LRU 的缓存驱逐
懒加载和部分加载大大减少了进入本地内存和磁盘的数据量。但是,在长期运行的系统中,缓存仍会随着新数据的访问而增长。当达到本地容量时,基于 LRU 的缓存驱逐就会生效。
LRU(最近最少使用)驱逐遵循一个简单的规则:首先驱逐最近未被访问的数据。这就为新访问的数据腾出了本地空间,同时将常用数据保留在缓存中。
性能评估:分层存储与满载
为了评估分层存储在现实世界中的影响,我们建立了一个与生产工作负载密切相关的测试环境。我们从加载时间、资源使用情况、查询性能、有效容量和成本效益五个方面,对 Milvus 分层存储和不分层存储进行了比较。
实验设置
数据集
1 亿个向量,768 个维度(BERT 嵌入向量)
向量索引大小:约 430 GB
10 个标量字段,包括 ID、时间戳和类别
硬件配置
1 个 QueryNode,带 4 个 vCPU、32 GB 内存和 1 TB NVMe SSD
10 Gbps 网络
MinIO 对象存储集群作为远程存储后端
访问模式
查询遵循现实的冷热访问分布:
80% 的查询以最近 30 天的数据为目标(≈ 数据总量的 20)
15% 的查询针对 30-90 天内的数据(≈ 数据总量的 30)
5%的查询以超过 90 天的数据为目标(≈ 数据总量的 50)
主要结果
1.加载时间快 33 倍
| 阶段 | Milvus 2.5 | Milvus 2.6+(分层存储) | 加速 |
|---|---|---|---|
| 数据下载 | 22 分钟 | 28 秒 | 47× |
| 索引加载 | 3 分钟 | 17 秒 | 10.5× |
| 总计 | 25 分钟 | 45 秒 | 33× |
在 Milvus 2.5 中,加载 Collections 需要25 分钟。在 Milvus 2.6+ 中使用分层存储后,同样的工作负载只需45 秒就能完成,这意味着负载效率有了质的飞跃。
2.本地资源使用减少 80
| 阶段 | Milvus 2.5 | Milvus 2.6+ (分层存储) | 减少 |
|---|---|---|---|
| 加载后 | 430 GB | 12 GB | -97% |
| 1 小时后 | 430 GB | 68 GB | -84% |
| 24 小时后 | 430 GB | 85 GB | -80% |
| 稳定状态 | 430 GB | 85-95 GB | ~80% |
在 Milvus 2.5 中,无论工作负荷或运行时间如何,本地资源使用量始终保持在430 GB。相比之下,Milvus 2.6+ 在加载后立即开始使用的资源只有12 GB。
随着查询的运行,频繁访问的数据被本地缓存,资源使用量逐渐增加。大约 24 小时后,系统稳定在85-95 GB,反映了热数据的工作集。从长远来看,这使得本地内存和磁盘的使用量减少了约 80%,而查询的可用性却没有受到影响。
3.对热数据性能的影响几乎为零
| 查询类型 | Milvus 2.5 P99 延迟 | Milvus 2.6+ P99 延迟 | 变化 |
|---|---|---|---|
| 热数据查询 | 15 毫秒 | 16 毫秒 | +6.7% |
| 热数据查询 | 15 毫秒 | 28 毫秒 | +86% |
| 冷数据查询(首次访问) | 15 毫秒 | 120 毫秒 | +700% |
| 冷数据查询(缓存) | 15 毫秒 | 18 毫秒 | +20% |
对于约占所有查询 80% 的热数据,P99 延迟只增加了 6.7%,对生产几乎没有影响。
冷数据查询由于按需从对象存储加载,首次访问时的延迟较高。不过,一旦缓存,其延迟仅增加 20%。鉴于冷数据的访问频率较低,对于大多数实际工作负载来说,这种权衡通常是可以接受的。
4.4.3 倍的有效容量
在相同的硬件预算下--8 台服务器,每台 64 GB 内存(总计 512 GB)--Milvus 2.5 最多可加载 512 GB 的数据,相当于约 1.36 亿个向量。
在 Milvus 2.6+ 中启用分层存储后,同样的硬件可以支持 2.2 TB 的数据,大约相当于 5.9 亿个向量。这意味着有效容量增加了 4.3 倍,从而可以在不扩展本地内存的情况下为更大的数据集提供服务。
5.成本降低 80.1%
以 AWS 环境中的 2 TB 向量数据集为例,假设 20% 的数据为热数据(400 GB),成本对比如下:
| 项目 | Milvus 2.5 | Milvus 2.6+(分层存储) | 节省 |
|---|---|---|---|
| 每月成本 | $11,802 | $2,343 | $9,459 |
| 年度费用 | $141,624 | $28,116 | $113,508 |
| 节余率 | - | - | 80.1% |
基准总结
在所有测试中,分层存储都实现了一致且可衡量的改进:
加载时间快 33 倍:Collections 加载时间从25 分钟缩短到 45 秒。
本地资源使用率降低 80%:在稳态操作符下,内存和本地磁盘使用率降低了约80%。
对热数据性能的影响几乎为零:热数据的 P99 延迟增加不到 10%,从而保持了低延迟查询性能。
控制冷数据的延迟:冷数据在首次访问时会产生较高的延迟,但鉴于其访问频率较低,这种延迟是可以接受的。
有效容量提高 4.3 倍:同样的硬件在不增加内存的情况下,可提供多 4-5 倍的数据。
成本降低 80% 以上:年度基础设施成本降低80% 以上。
何时在 Milvus 中使用分层存储
根据基准测试结果和实际生产案例,我们将分层存储使用案例分为三类,以帮助您决定是否适合您的工作负载。
最适合的使用案例
1.多租户向量搜索平台
特点:租户数量多,活动极不均衡;向量搜索是核心工作负载。
访问模式:不到 20% 的租户产生 80% 以上的向量查询。
预期效益成本降低 70-80%;容量扩大 3-5倍。
2.电子商务推荐系统(向量搜索工作负载)
特点顶级产品和长尾产品之间的流行度偏差很大。
访问模式:前 10% 的产品占向量搜索流量的约 80%。
预期效益高峰期无需额外容量;成本降低 60-70
3.冷热分明的大规模数据集(向量为主)
特点TB 级或更大规模的数据集,访问严重偏向于最近的数据。
访问模式:典型的 80/20 分布:20% 的数据为 80% 的查询服务
预期效益成本降低 75-85
合适的使用案例
1.成本敏感型工作负载
特点:预算紧张,但可承受轻微的性能折衷。
访问模式:向量查询相对集中。
预期效益成本降低 50-70%;首次访问冷数据可能会产生 ~500 毫秒的延迟,应根据 SLA 要求进行评估。
2.历史数据保留和存档搜索
特点:大量历史向量,查询频率极低。
访问模式:约 90% 的查询以近期数据为目标。
预期效益保留完整的历史数据集;保持基础设施成本的可预测性和可控性
不适合的使用案例
1.统一热数据工作负载
特征:所有数据的访问频率相似,没有明显的冷热之分。
不适合的原因高速缓存效益有限;增加了系统复杂性,却没有显著收益
2.超低延迟工作负载
特点对延迟极为敏感的系统,如金融交易或实时竞价
为什么不适合?即使是微小的延迟变化也是不可接受的;满载可提供更可预测的性能
快速入门:在 Milvus 2.6+ 中尝试分层存储
# Download Milvus 2.6.1+
$ wget https://github.com/milvus-io/milvus/releases/latest
# Configure Tiered Storage
$ vi milvus.yaml
queryNode.segcore.tieredStorage:
warmup:
scalarField: disable
scalarIndex: disable
vectorField: disable
vectorIndex: disable
evictionEnabled: true
# Launch Milvus
$ docker-compose up -d
结论
Milvus 2.6 中的分层存储解决了向量数据存储方式与实际访问方式之间常见的不匹配问题。在大多数生产系统中,只有一小部分数据会被频繁查询,而传统的加载模型却将所有数据视为同样热的数据。通过转向按需加载并将本地内存和磁盘作为缓存来管理,Milvus 使资源消耗与实际查询行为而不是最坏情况假设保持一致。
这种方法允许系统在不按比例增加本地资源的情况下扩展到更大的数据集,同时保持热查询性能基本不变。冷数据在需要时仍可访问,并具有可预测和有限制的延迟,从而使权衡变得清晰可控。随着向量搜索深入到成本敏感、多租户和长期运行的生产环境中,分层存储为大规模高效操作提供了实用的基础。
有关分层存储的更多信息,请查看下面的文档:
有问题或想深入了解最新 Milvus 的任何功能?加入我们的 Discord 频道或在 GitHub 上提交问题。您还可以通过 Milvus Office Hours 预订 20 分钟的一对一课程,以获得见解、指导和问题解答。
了解有关 Milvus 2.6 功能的更多信息
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word



