首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Elasticsearch Serverless 如何将向量搜索吞吐量提升一倍

Elasticsearch Serverless 如何将向量搜索吞吐量提升一倍

作者头像
点火三周
发布2026-05-29 13:48:22
发布2026-05-29 13:48:22
890
举报
文章被收录于专栏:Elastic Stack专栏Elastic Stack专栏

Elasticsearch Serverless 如何将向量搜索吞吐量提升一倍

从向量搜索到强大的 REST API,Elasticsearch 为开发者提供了最全面的搜索工具集。您可以查阅 Elasticsearch Labs 代码库 中的示例笔记本,体验新功能。您也可以立即开启免费试用或在本地运行 Elasticsearch。

我们已将 simdvec,即 Elasticsearch 原生的单指令多数据 (SIMD) 向量评分引擎,引入了 serverless 环境。在并发负载下,搜索吞吐量几乎翻倍,p99.9 尾部延迟从 237 毫秒降至 30 毫秒。通过让 simdvec 直接访问 blob 缓存的内存映射区域,serverless 现在能够运行与 stateful 版本相同的零拷贝 SIMD 内核,同时保持相同的召回率且零堆开销。由于 serverless 赋予我们对整个存储层的控制权,我们相信它将成为 向量搜索速度最快的地方。以下是我们的实现过程。

Elasticsearch Serverless 上的向量搜索

Elasticsearch Serverless 基于 Stateless Elasticsearch 构建,这是一种完全解耦的计算和存储架构,其中索引数据存储在远程对象存储中,而搜索节点仅维护本地缓存。为了在这种架构下实现快速的向量搜索,评分引擎需要直接与本地缓存协同工作,而不是先将其复制到堆内存。

Elasticsearch 的 simdvec 是 Elasticsearch 中所有向量距离计算的幕后引擎。它提供经过精心调优的 AVX-512 和 NEON 内核、带有显式预取功能的批量评分,以及堆外内存访问,确保数据直接从存储流向 CPU 寄存器。在 stateful Elasticsearch 上,simdvec 始终拥有直接的“燃料线”:内存映射文件将原生指针直接输入到 SIMD 内在函数中。而在 serverless 环境中,数据虽然就位于 blob 缓存的内存映射区域中,形式也完全正确,但却没有路径将其连接到评分引擎。

现在,我们已经构建了这条路径。simdvec 在 Serverless 上运行,具备与 stateful 版本相同的堆外原生 SIMD 评分能力。而且,由于 serverless 赋予我们对整个存储层的控制权,这仅仅是个开始。

仅限高级燃料:simdvec 为何需要堆外内存进行向量评分

simdvec 的速度源于直接操作堆外内存。它获取一个指向内存映射数据的原生指针,并将其直接传递给 C++ SIMD 内在函数。没有中间拷贝,也没有堆分配。数据直接从存储流向 CPU 寄存器。这比听起来更重要:simdvec 的内核处理向量的速度比数据复制的速度还要快,因此路径中的任何复制都会成为瓶颈,而不是评分本身。

在 stateful Elasticsearch 上,这自然而然地就实现了。Lucene 将索引文件从本地磁盘内存映射,评分器直接从映射区域提取原生指针。正是这条路径,带来了我们已发布的基准测试数据,这也是我们希望引入 serverless 的功能。要了解如何实现,我们首先需要理解 serverless 如何存储和访问数据。

Serverless blob 缓存:Elasticsearch 如何存储向量数据

在无状态架构中,所有索引数据的主副本都存储在远程对象存储(如 S3)中。每个搜索节点都维护一个本地缓存(称为 blob 缓存),用于将最近和频繁访问的索引数据部分保留在本地 SSD 上。stateful Elasticsearch 上的 frozen tier 使用相同的架构:Searchable snapshots 由类似的 blob 缓存支持,该缓存将远程存储的区域内存映射到本地磁盘。当搜索命中缓存数据时,它将从快速本地存储中提供服务。当未命中时,blob 缓存会从远程存储中获取数据并进行缓存以供将来查询。

blob 缓存被组织成固定大小的内存映射区域,默认为 16MB。它管理自身的生命周期:跟踪哪些区域正在使用中,当缓存满时应用最近最少使用淘汰策略,并进行引用计数以确保区域在读取时不会被淘汰。这些区域仍然通过操作系统进行内存映射,但 blob 缓存控制哪些区域存在、哪些区域被填充以及何时被回收。在 stateful 环境中,这些决策完全留给操作系统。

此图显示了远程对象存储和 simdvec 之间的数据流。顶部标有“远程对象存储”的框列出了 S3、GCS 和 Azure Blob,并有一个标有“未命中时获取”的箭头指向一个更大的框,标有“Blob 缓存”。Blob 缓存内部有编号为 0-5 的区域以及两个空槽,每个区域 16 MB。区域 0、1、3、4 为绿色并标记为“已缓存”,区域 2 为蓝色并标记为“使用中”,区域 5 为黄色并标记为“正在淘汰”,另有两个灰色框标记为“空”。图例解释了颜色代码。一个标有“直接内存”的向下箭头连接 Blob 缓存到一个深色框,标有“simdvec – 原生 SIMD 评分”。
此图显示了远程对象存储和 simdvec 之间的数据流。顶部标有“远程对象存储”的框列出了 S3、GCS 和 Azure Blob,并有一个标有“未命中时获取”的箭头指向一个更大的框,标有“Blob 缓存”。Blob 缓存内部有编号为 0-5 的区域以及两个空槽,每个区域 16 MB。区域 0、1、3、4 为绿色并标记为“已缓存”,区域 2 为蓝色并标记为“使用中”,区域 5 为黄色并标记为“正在淘汰”,另有两个灰色框标记为“空”。图例解释了颜色代码。一个标有“直接内存”的向下箭头连接 Blob 缓存到一个深色框,标有“simdvec – 原生 SIMD 评分”。

此图显示了远程对象存储和 simdvec 之间的数据流。顶部标有“远程对象存储”的框列出了 S3、GCS 和 Azure Blob,并有一个标有“未命中时获取”的箭头指向一个更大的框,标有“Blob 缓存”。Blob 缓存内部有编号为 0-5 的区域以及两个空槽,每个区域 16 MB。区域 0、1、3、4 为绿色并标记为“已缓存”,区域 2 为蓝色并标记为“使用中”,区域 5 为黄色并标记为“正在淘汰”,另有两个灰色框标记为“空”。图例解释了颜色代码。一个标有“直接内存”的向下箭头连接 Blob 缓存到一个深色框,标有“simdvec – 原生 SIMD 评分”。

至关重要的是,由于每个区域都是内存映射的,blob 缓存已经以 simdvec 所需的精确形式保存了向量数据。但在我们建立连接之前,无法访问这些数据。每个向量比较都被复制到一个堆数组中,并交给一个较慢的评分器。没有直接内存指针,没有 SIMD,并且每次调用都会产生垃圾回收压力。

统一评分:所有存储层共用一个 SIMD 路径

我们引入了一个新的抽象层,允许评分器安全地从底层存储层借用直接内存,时间刚好足够运行 SIMD 计算。如果数据作为直接内存可用,simdvec 的原生内核就会运行。如果不可用(数据尚未缓存或跨越区域边界),评分器会回退到堆拷贝。实际上,回退的情况很少发生。

并排比较图,标题为“之前”和“之后”。“之前”部分显示四个框:蓝色“Stateful – 本地 mmap”、绿色“simdvec – 原生 SIMD ✓”、黄色“Serverless – blob 缓存”和红色“Java 评分器 – 无 SIMD ✗”。箭头表示从 Stateful 到 simdvec 的绿色“直接指针”以及从 Serverless 到 Java 评分器的红色“堆拷贝”,并配有说明文字“两条路径,两种实现”。“之后”部分显示三个框:蓝色“Stateful – 本地 mmap”、黄色“Serverless – blob 缓存”和绿色“simdvec – 原生 SIMD ✓”,并有两个标有“直接”的绿色箭头指向 simdvec,配有说明文字“一个引擎,一个代码路径,所有层。”

这为我们提供了跨所有层的单一评分入口点:

  1. 1. Stateful(本地磁盘):评分器从操作系统内存映射中提取原生指针。
  2. 2. Blob 缓存(serverless、frozen tier):评分器从缓存区域借用直接内存切片。
  3. 3. 回退:评分器将字节复制到堆内存。实际上很少发生。

评分器不知道它运行在哪一层,也不需要知道。这也意味着我们不再需要维护单独的评分实现;以前,stateful 有一个快速的原生路径,而其他所有层都有一个较慢的路径。现在,simdvec 的每一次改进都会自动惠及所有层,包括其最强大的功能:批量评分。

跨 blob 缓存区域的批量向量评分

单个查询可能需要对数千个候选向量进行评分。simdvec 的批量评分通过多累加器内循环、查询分摊和缓存行预取来批量处理这些向量,当数据超出 CPU 缓存时,其速度比单向量替代方案快 4 倍。

对倒排文件 (IVF) 索引的搜索是批量评分发挥最大作用的地方。查询选择一组候选倒排列表,并扫描量化向量,批量地对它们与查询向量进行评分。在 stateful 环境中,这些向量位于一个连续的内存映射文件中,因此批量评分通过直接的指针算术解析它们,并在单个原生调用中对一批向量进行评分。

在 serverless 环境中,遍历倒排列表可能会跨越 blob 缓存区域边界。我们通过批量访问方法扩展了直接内存抽象,该方法在一次调用中将多个向量偏移量解析到各自的缓存区域。如果批次中的所有向量都已缓存且没有跨越区域边界,评分器将获得一个直接内存切片,并将整个批次传递给 simdvec 的原生批量内核,其预取和流水线处理与 stateful 版本相同。当向量确实跨越边界时,系统会回退到按向量评分:仍然是零拷贝,只是没有批量处理的优势。对于 16MB 区域和 1024 字节向量,这种情况大约每 16,000 个向量发生一次。

simdvec 的批量评分架构是 simdvec 基准测试中强调的关键差异化优势,现在它在 serverless 上运行,并具有与在 stateful 环境中相同的速度特性。那么,它在实践中的表现如何呢?

Elasticsearch Serverless 上的 simdvec:向量搜索耗时

我们使用一个包含 1800 万个向量的 MSMARCO 数据集进行基准测试,维度为 1024,并使用带有 Better Binary Quantization (BBQ) 1 位量化的 IVF。所有结果均在热 blob 缓存且完整数据集驻留在本地缓存区域的情况下获得,因此我们测量的是评分路径而不是远程获取延迟。

吞吐量。 在并发负载下,搜索吞吐量几乎翻倍,从 398 ops/s 跃升至 739 ops/s。单客户端的增益为 23-39%,但在并发下真正的差异显现出来:改进幅度是 2-3 倍,因为消除堆拷贝消除了以前限制并发评分的 GC 压力和分配争用。

条形图,标题为“搜索吞吐量 — 基线对比零拷贝(中位数 ops/s)”。它比较了八种 knn 配置下基线(堆拷贝)和零拷贝(DirectAccessInput)之间的中位数吞吐量。每组显示一个灰色基线条和一个更高的绿色零拷贝条,上方标有百分比改进。Y 轴显示每秒操作数的中位数吞吐量,范围高达 900。副标题指出百分比标签表示改进。
条形图,标题为“搜索吞吐量 — 基线对比零拷贝(中位数 ops/s)”。它比较了八种 knn 配置下基线(堆拷贝)和零拷贝(DirectAccessInput)之间的中位数吞吐量。每组显示一个灰色基线条和一个更高的绿色零拷贝条,上方标有百分比改进。Y 轴显示每秒操作数的中位数吞吐量,范围高达 900。副标题指出百分比标签表示改进。

条形图,标题为“搜索吞吐量 — 基线对比零拷贝(中位数 ops/s)”。它比较了八种 knn 配置下基线(堆拷贝)和零拷贝(DirectAccessInput)之间的中位数吞吐量。每组显示一个灰色基线条和一个更高的绿色零拷贝条,上方标有百分比改进。Y 轴显示每秒操作数的中位数吞吐量,范围高达 900。副标题指出百分比标签表示改进。

尾部延迟。 直接内存路径在负载下显著改善了尾部延迟:

  • p99.9 从 237 毫秒降至 30 毫秒(降低 87%)。
  • p99.99 从 9.1 秒降至 55 毫秒(降低 99.4%)。

p100 从 11.4 秒降至 100 毫秒以下。

折线图,标题为“尾部延迟急剧下降 — knn-10-10 多客户端”。该图比较了在对数刻度下,基线(堆拷贝)和零拷贝(DirectAccessInput)在 p50 到 p100 百分位之间的延迟。红色基线急剧上升,而绿色零拷贝线保持在低位。标签标记了关键点。图注说明了 Rally 基准测试细节和对数刻度。
折线图,标题为“尾部延迟急剧下降 — knn-10-10 多客户端”。该图比较了在对数刻度下,基线(堆拷贝)和零拷贝(DirectAccessInput)在 p50 到 p100 百分位之间的延迟。红色基线急剧上升,而绿色零拷贝线保持在低位。标签标记了关键点。图注说明了 Rally 基准测试细节和对数刻度。

折线图,标题为“尾部延迟急剧下降 — knn-10-10 多客户端”。该图比较了在对数刻度下,基线(堆拷贝)和零拷贝(DirectAccessInput)在 p50 到 p100 百分位之间的延迟。红色基线急剧上升,而绿色零拷贝线保持在低位。标签标记了关键点。图注说明了 Rally 基准测试细节和对数刻度。

以前需要数秒才能完成的最差情况下的异常值,现在只需数十毫秒。由堆拷贝引起的排队导致的延迟峰值已不复存在。

召回率保持不变。对相同的向量进行评分,产生相同的结果。而这仅仅是个开始。

超越对等:Elasticsearch Serverless 在向量搜索方面能做到 stateful 无法做到的事

达到与 stateful 版本对等是我们的目标。但更有趣的认识是,无状态架构让我们能够做到 stateful 无法做到的事情。

在 stateful 环境中,操作系统控制内存映射文件的行为:哪些页面常驻内存,何时淘汰,以及预读的积极程度。应用程序可以提供提示,但它们适用于整个文件映射,并且内核可能会忽略它们。更糟糕的是,搜索和索引在同一节点上并发发生,因此有利于一种访问模式的提示可能会损害另一种访问模式。实际上,为了平衡不同的需求,您必须采取保守策略。

在 serverless 环境中,有两点根本不同。blob 缓存以完全的应用程序级控制管理自己的内存映射区域。并且 serverless 将索引和搜索分离到专用层:搜索节点从不合并,索引节点从不处理查询。没有冲突的访问模式意味着我们可以积极地提供内存建议。以下是我们正在进行的工作:

  • 按区域的内存建议。 blob 缓存知道每个区域存储什么类型的数据。它可以为重新评分区域发出随机访问提示,在这些区域中,原始 float32 向量以不可预测的顺序读取,内核的默认预读会浪费内存到永远不会使用的页面上。它可以为扫描量化向量应用顺序预读。在索引层,合并操作顺序读取数据,因此积极的预读会在需要页面之前将其加载进来,而不会有损害并发随机读取的风险,因为这些读取根本不会在该节点上发生。
  • 缓存感知的预取。 simdvec 已经在 CPU 缓存行级别进行预取。在 serverless 环境中,我们可以将其与 blob 缓存的区域驻留知识进行协调,在多个级别进行预取:从远程存储到缓存,从操作系统页面到 RAM,以及从缓存行到 CPU。blob 缓存可以告知评分器在评分开始前哪些区域是驻留的,从而避免对会触发远程获取的数据进行操作。
  • 工作负载感知的淘汰。 blob 缓存可以优先保留向量搜索所依赖的数据:例如在每次查询时都会检查的 IVF 质心索引,或批量评分的量化向量,而不是那些不经常访问的数据。操作系统页面缓存根据通用启发式算法进行淘汰,它不了解数据代表什么。在 serverless 环境中,淘汰策略可以根据工作负载进行调整。

blob 缓存赋予我们对内存层次结构的控制级别是操作系统页面缓存无法比拟的。这就是为什么我们认为 serverless 是下一代向量搜索性能工作的最有前景的平台。不仅要与 stateful 匹配,还要超越它。而向量只是一个开始。

Elasticsearch Serverless 上的向量搜索:我们发布了什么以及下一步是什么

simdvec 现在在 Elasticsearch 运行的所有地方(stateful、serverless 和 frozen tier)都以相同的原生 SIMD 评分、相同的批量评分和相同的堆外效率运行。我们构建的抽象是通用目的的,并且已经通过存储链中的每一层进行连接,因此相同的方法将来可以使术语查找、聚合、排序和存储字段检索受益。

Elasticsearch Serverless 是我们对向量搜索性能投入最大的地方。simdvec 的每一次改进、blob 缓存的每一次优化以及存储层面的每一次新改进都将首先在这里实现。如果您正在选择运行向量工作负载的平台,serverless 是一个不断提速的平台。您可以从免费的 Elastic Cloud 试用版 开始。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-05-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 点火三周 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Elasticsearch Serverless 如何将向量搜索吞吐量提升一倍
    • Elasticsearch Serverless 上的向量搜索
    • 仅限高级燃料:simdvec 为何需要堆外内存进行向量评分
    • Serverless blob 缓存:Elasticsearch 如何存储向量数据
    • 统一评分:所有存储层共用一个 SIMD 路径
    • 跨 blob 缓存区域的批量向量评分
    • Elasticsearch Serverless 上的 simdvec:向量搜索耗时
    • 超越对等:Elasticsearch Serverless 在向量搜索方面能做到 stateful 无法做到的事
    • Elasticsearch Serverless 上的向量搜索:我们发布了什么以及下一步是什么
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档