快 12 倍的 Elasticsearch 向量索引:使用 GPU 和 CPU 分层部署 NVIDIA cuVS

作者:来自 Elastic Blake Holden

在 Elasticsearch 中部署 NVIDIA cuVS GPU 加速 HNSW 索引的两种模式:适用于小型集群的构建与服务一体化节点,以及适用于大规模生产环境、通过 ILM 切换到 CPU 的专用 GPU 摄取层。

从向量搜索到强大的 REST API, Elasticsearch 为开发者提供了最全面的搜索工具集。深入体验 Elasticsearch Labs 仓库中的示例 notebooks,尝试一些新内容。你也可以立即开始免费试用,或者今天就在本地运行 Elasticsearch。


NVIDIA cuVS 在 GPU 上构建 HNSW 图,在 Elasticsearch 中实现最高快 12 倍的向量索引速度。本文介绍了两种生产部署模式:模式 A 在同一个 GPU 节点上同时执行构建和服务,适用于少于五个数据节点的集群。模式 B 使用三个精简 GPU 摄取节点(每个 64 GB RAM),并通过 ILM rollover 切换到七个 CPU 热服务节点(每个 192 GB)------ 这是大规模生产环境下默认的正确选择。文中还包含完整的索引模板、 ILM 策略,以及针对 3 亿向量语料库的容量计算。

Elasticsearch cuVS GPU 插件实际上做了什么?

Elasticsearch cuVS GPU 插件会在两个操作期间接管 HNSW 图构建:segment flush 和 force merge。该插件要求数据节点连接受支持的 NVIDIA GPU、安装 cuVS 插件,并在 elasticsearch.yml 中设置 vectors.indexing.use_gpu: true

  • Segment flush 。向量会累积在 JVM 写缓冲区中。在 flush 时,插件会对这些向量进行批处理,通过 PCIe 将它们复制到 GPU VRAM,在 VRAM 中构建 CAGRA 图,将其转换为 HNSW,然后再通过 PCIe 将结果复制回系统 RAM,随后 Lucene 将 segment 文件写入本地 NVMe。之后,该 segment 会被 memory-map 到操作系统页缓存中,用于查询服务。
  • Force merge。当 segment 被合并时,相同的 GPU 路径会加速图重建。根据已发布的基准测试, force merge 时间大约可提升 7 倍。

其他所有内容(HTTP 请求处理、查询服务、集群状态管理、ILM 执行)都运行在 CPU 上,并使用系统 RAM。GPU 是两个写路径操作的协处理器,而不是主机计算环境的替代品。

将 GPU 构建与 CPU 查询服务分离这一点非常重要,因为连接 GPU 的节点不需要承担查询服务层角色。它们可以专门用于写路径,并将构建完成的 shard 转交给成本更低的 CPU 热服务节点。这正是模式 B 背后的核心思想。

模式 A:在单个 Elasticsearch 节点中同时进行 GPU 构建与服务

模式 A 是更简单的部署方式。每个 GPU 节点既负责构建 shard,也负责对这些 shard 提供查询服务。这也是运行 cuVS 基准测试时采用的方式:单个 g6.4xlarge(64 GB RAM、1 个 NVIDIA L4)在单个 Elasticsearch 进程上执行索引。该节点能够同时处理索引和搜索,不过已发布的基准测试主要测量的是索引吞吐量。

何时使用组合式 GPU 节点(模式 A)

  • 小型集群(少于 5 个数据节点)

  • 概念验证或边缘部署,在这些场景下,运维简洁性比成本优化更重要

  • 语料库规模足够小,以至于完整 HNSW 图能够与正常运行负载一起放入每个节点的页缓存中

节点配置(模式 A)

每个数据节点都配备 GPU,并使用相同的 elasticsearch.yml 配置:

复制代码
# elasticsearch.yml: Pattern A (combined GPU + serving node)
node.roles: [data_hot, data_content]

# auto (default): use GPU when available. true: fail to start if GPU unavailable.
# Use true on dedicated GPU nodes to catch misconfiguration at boot.
vectors.indexing.use_gpu: true

# JVM heap: ~32 GB max (compressed OOPs boundary)
# Remaining system RAM goes to OS page cache for HNSW graph

不需要任何 shard 路由技巧,也不需要 ILM 分层隔离。Shard 会按照 Elasticsearch 默认分配器的规则进行分配,并且每个节点都可以同时进行构建与服务。

注意 :还有一个索引级别设置 index.vectors.indexing.use_gpu,它可以按索引覆盖节点级默认配置。有效值包括:

  • auto(默认值,在 GPU 可用时使用 GPU)

  • true(要求必须有 GPU,如果不可用则失败)

  • false(为该索引禁用 GPU)

容量规划影响

由于每个节点都持有长期存在的 shard,因此它需要足够的系统 RAM 来支持:

  • JVM heap(约 32 GB)

  • 用于保存其对应语料库 HNSW 图的操作系统页缓存

  • 操作系统和 CUDA 开销(约 10--15 GB)

对于一个包含 3 亿向量、启用 HA(两份副本)的 int8 语料库,10 个数据节点中的每个节点大约需要在页缓存中保存 65 GB 的 HNSW 数据。再加上 JVM 和其他开销后,每个节点大约需要 128--192 GB 系统 RAM。这远高于 64 GB 的参考基准配置,因为该基准只是在单节点上保存了 260 万个向量。

每个节点的系统 RAM 是随着每节点 shard 数量增长的,而不是随着整个语料库大小增长。你可以选择更多节点配更少 RAM,或者更少节点配更多 RAM。两者之间的权衡在于运维复杂度与硬件成本。

关于已发布基准测试的说明

约 12 倍的索引吞吐提升以及约 7 倍的 force merge 提升,是在单个 g6.4xlarge 节点上,使用 260 万个、1536 维的 float32 hnsw 向量测得的。本文中的示例则使用了 1024 维的 int8_hnsw。不同维度数量和量化级别会影响性能特征,因此在生产环境容量规划之前,请先针对你自己的语料库进行基准测试。

模式 B:通过 ILM shard 切换到 CPU 的专用 GPU 摄取节点

模式 B 将集群拆分为两个数据层,每个层具有不同的硬件配置和职责:

  • GPU 摄取层。少量配备 NVIDIA GPU 和适度系统 RAM(64 GB)的节点。这些节点负责接收写入、通过 cuVS 在 GPU 上构建 HNSW segment,并持有当前活跃写 shard。
  • CPU 热服务层。更多不带 GPU、但拥有更大系统 RAM(192 GB)的节点。这些节点通过 ILM rollover 从 GPU 摄取层接收迁移过来的 shard,并承担所有查询流量。

一旦 shard rollover 并迁移到 CPU 热服务层后,GPU 摄取节点将不再持有该 shard。由于 GPU 摄取节点始终只保存当前正在写入的索引,因此它的页缓存占用会保持较小。

何时使用 GPU 摄取 + CPU 服务(模式 B)

  • 生产集群拥有 5 个以上数据节点,并且已经将 ILM rollover 作为日常运维流程的一部分

  • GPU 硬件成本较高,并且你希望尽可能减少需要 GPU 的节点数量

  • 查询服务工作负载需要专用 CPU 和 RAM,而不希望与 GPU 构建操作共享资源

  • ILM 已经是现有运维模型的一部分(对于任何时序型或生命周期管理的向量语料库来说,本就应该如此)

节点配置(模式 B)

GPU 摄取节点(elasticsearch.yml):

复制代码
# GPU ingest node: builds shards, does not serve queries long-term
node.roles: [data_hot]
node.attr.tier_function: gpu_ingest

vectors.indexing.use_gpu: true

CPU 热服务节点(elasticsearch.yml):

复制代码
# CPU hot-serving node: receives migrated shards, serves queries
node.roles: [data_hot]
node.attr.tier_function: cpu_serve

两种节点类型都共享 data_hot 角色,因为它们属于同一个逻辑层。自定义属性 node.attr.tier_function 让我们能够控制哪些节点接收新的写入,以及哪些节点接收迁移后的 shard。

索引模板:将新的写入路由到 GPU 节点

复制代码
PUT _index_template/vectors-template
{
  "index_patterns": ["vectors-*"],
  "template": {
    "settings": {
      "index.routing.allocation.require.tier_function": "gpu_ingest",
      "index.lifecycle.name": "vectors-lifecycle",
      "index.lifecycle.rollover_alias": "vectors-active"
    },
    "mappings": {
      "properties": {
        "embedding": {
          "type": "dense_vector",
          "dims": 1024,
          "index": true,
          "index_options": {
            "type": "int8_hnsw"
          }
        }
      }
    }
  }
}

匹配 vectors-* 的新索引会被专门分配到具有 tier_function: gpu_ingest 的节点上。写入会流向 GPU 摄取节点,并由 cuVS 在 GPU 上构建 HNSW 图。

关键点:你必须显式设置 index_options.typeint8_hnsw(或 hnsw)才能启用 GPU 加速 。在 Elasticsearch 9.1 及以上版本中,维度为 384 或更高的 dense_vector 字段默认使用 bbq_hnsw,而 cuVS 不支持该类型。如果你在模板之外创建向量字段但没有指定 int8_hnsw,GPU 插件将在索引构建时回退到 CPU。上面的模板已经正确设置,但集群中所有希望使用 cuVS 加速的向量字段都必须显式配置这一项。

ILM 策略:滚动更新并迁移到 CPU 服务节点

复制代码
PUT _ilm/policy/vectors-lifecycle
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_age": "7d",
            "max_primary_shard_size": "50gb"
          },
          "set_priority": {
            "priority": 100
          }
        }
      },
      "warm": {
        "min_age": "0ms",
        "actions": {
          "migrate": {
            "enabled": false
          },
          "allocate": {
            "require": {
              "tier_function": "cpu_serve"
            }
          },
          "set_priority": {
            "priority": 50
          }
        }
      },
      "cold": {
        "min_age": "180d",
        "actions": {
          "migrate": {
            "enabled": false
          },
          "allocate": {
            "require": {
              "tier_function": "cpu_serve"
            }
          }
        }
      },
      "delete": {
        "min_age": "730d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

这个策略里有几个需要注意的点。

在 warm 和 cold 阶段里,"**migrate": {"enabled": false}**很关键。warm 阶段的 migrate 操作通常会尝试把 _tier_preference 设置为 data_warm,但在这个架构中没有任何节点具备 data_warm 角色,如果启用 migrate,就可能导致 shard 无法分配。禁用 migrate,并使用基于 tier_function 自定义属性的显式 allocate 动作,可以精确控制 shard 的落点。

warm 阶段里的 min_age: "0ms" 表示在 rollover 之后立即迁移,而不是等待一段时间。这是有意设计的:我们希望 shard 在 rollover 后几分钟内就离开 GPU 摄取节点,从而保持 GPU 摄取层的轻量状态。

替代方案 :如果 "warm"(ILM 阶段名)和 "hot serving"(CPU 服务节点实际角色)之间的命名混淆对团队来说是个问题,也可以反过来设置 GPU 摄取节点为 node.roles: [data_hot],CPU 热服务节点为 node.roles: [data_warm],然后让 ILM 使用标准的 tier 迁移机制完成移动,而不需要自定义属性。这种方式的优点是 ILM 更简单,但语义可能有点反直觉:承担最重查询负载的节点会被标记为 "warm"。

为什么 GPU 摄取节点 64 GB 系统 RAM 就足够

在 Pattern B 中,GPU 摄取节点只需要承载以下内容(大致基于 Elasticsearch JVM 建议和 CUDA 运行时开销经验值):

消耗项 大致 RAM 占用
JVM heap ~32 GB
CUDA driver + pinned PCIe buffers ~10 GB
用于活跃写入 shard 的页缓存 ~10--15 GB
操作系统与容器开销 ~5 GB
总计 ~60 GB

这与已发布的 cuVS benchmark 硬件一致:AWS g6.4xlarge(64 GB RAM)。GPU 摄取节点不需要保存整个语料库累积的 HNSW 图,只需要保存当前正在写入的 index,该 index 会以较短周期进行 rollover。

相比之下,CPU 热服务节点需要在 page cache 中保存累积语料库,并且根据 vectors-per-node 的不同需要 128--192 GB。

容量规划总结(Pattern B,3 亿 vectors,int8_hnsw,HA)

节点类型 数量 系统 RAM GPU 角色
GPU 摄取 3 64 GB 1x L40S (48 GB VRAM) 构建 shards, cuVS
CPU 热服务 7 192 GB 提供查询服务,在 page cache 中保存 HNSW
Warm/cold( BBQ ) 5 64 GB 老化数据,约 8x 压缩
Masters 3 16 GB 集群仲裁
Coord + Kibana 4 32--64 GB 查询路由, Kibana UI

在 ECK 下的总 ERU(Elastic Resource Unit):约 ~32。

Pattern B 中的数据流(端到端)

在 Pattern B 中,向量从客户端进入 GPU 摄取节点,在该节点上由 cuVS 在 GPU 上构建 HNSW segment,然后通过 ILM 将完成的 shard 迁移到 CPU 热服务节点。下面的时序图展示了一批向量的完整往返流程,以及将已完成 shard 迁移到服务层的 rollover 过程:

步骤如下:

  1. 客户端发送 _bulk 请求,向量以 base64 字符串编码(推荐用于提升吞吐)。

  2. 协调节点将请求路由到拥有当前写入 shard 的 GPU 摄取节点。

  3. GPU 摄取节点的 JVM 解析请求,并将向量排入写入缓冲区。

  4. 达到 flush 阈值时,cuVS 插件对向量进行批处理,并通过 PCIe 将其从系统内存复制到 GPU VRAM。

  5. GPU 在 VRAM 中构建 CAGRA 图,并将其转换为 HNSW 格式。

  6. HNSW 数据通过 PCIe 从 GPU VRAM 复制回系统内存。

  7. Lucene 将 segment 文件从系统内存写入本地 NVMe。

  8. 该 segment 被 memory-map 到操作系统页缓存(系统内存中),并变为可查询状态。

  9. 达到配置的 rollover 阈值(按时间或大小)后,ILM 执行 rollover,在 GPU 摄取层创建新的写入 index。

  10. 已完成的 index 的分配条件从 gpu_ingest 变为 cpu_serve,Elasticsearch 的 shard allocator 将这些 shard 通过网络迁移到 CPU 热服务节点。

  11. CPU 热服务节点将接收到的 segment memory-map 到其页缓存中,并开始提供查询服务。

  12. GPU 摄取节点的页缓存随着 shard 的迁出而释放,为下一轮写入周期腾出空间。

  13. 在整个过程中,查询流量不会经过 GPU 摄取节点;GPU 也不会在 VRAM 中同时持有超过一个 batch 的向量。

  14. GPU 仅在步骤 4--6 处于忙碌状态,其余时间处于空闲。

  15. 系统内存在 GPU 前后都作为关键路径:一方面作为 PCIe 传输的 staging 区域,另一方面作为查询服务的持久 page cache。

添加 BBQ 冷层(带重量化)

Pattern B 还扩展出了用于长期存储语料的 BBQ 冷层。BBQ 相比 int8 大约提供 8 倍压缩,显著降低冷层的内存与磁盘占用。

ILM 策略会增加一个阶段,将 int8_hnsw 数据重新索引为使用 bbq_hnsw 配置的新 index:

复制代码
"cold": {
  "min_age": "180d",
  "actions": {
    "allocate": {
      "require": {
        "tier_function": "cpu_serve"
      }
    }
  }
}

实际上,重新量化是通过在冷阶段转换时触发的独立 reindex 作业来完成的。BBQ 相比 int8 大约提供 8 倍压缩(相比 float32 约 32 倍压缩),因此冷层的 RAM 和磁盘占用会大幅下降。

需要注意的是,BBQ 是纯 CPU 的量化路径。截至 Elasticsearch 9.5,cuVS 并不支持 bbq_hnsw。因此 GPU 摄取层使用 int8_hnsw 来构建,而 BBQ 的转换发生在之后的 CPU warm 或 cold 节点上。冷路径不依赖 GPU。

应该选择哪种模式?

对于大多数拥有 5 个或更多数据节点的生产集群,Pattern B 是更好的默认选择。Pattern A 则更适合概念验证部署和小型集群,在这些场景中,运维简单性比成本优化更重要。

因素 Pattern A(组合式) Pattern B(专用 GPU 摄取)
集群规模 少于 ~5 个数据节点 5+ 数据节点
运维复杂度 更低 更高(ILM + 分配路由)
GPU 节点系统 RAM 128--192 GB 64 GB
GPU 利用率 GPU 在查询期间处于空闲(无负载) GPU 在 flush 间隙空闲,但节点不承载查询
硬件成本 更高(每个 GPU 节点都需要查询级 RAM) 更低(GPU 摄取节点更精简)
ERU 影响 更高 更低
最佳适用场景 POC 或边缘部署 5+ 数据节点的生产环境

对于大多数生产部署来说,Pattern B 是更好的默认选择。运维复杂度是适中的(本文中展示的 ILM 策略和分配属性就是全部实现),并且 GPU 节点 RAM 和 ERU 的节省是显著的。

开始使用 NVIDIA cuVS GPU 向量索引

GPU 加速向量索引在 Elasticsearch 9.3 中作为技术预览提供(自管 Enterprise 版本),并计划在 Elasticsearch 9.5 中进入 GA(正式可用)。

要求:

  • Elasticsearch 9.3+ 且具备 Enterprise 订阅
  • NVIDIA Ampere 架构或更新 GPU(计算能力 ≥ 8.0),最少 8 GB VRAM
  • CUDA 12.x 和 cuVS 运行时库(具体支持版本参考 Elastic 支持矩阵
  • GPU 节点上 Java 22 或更高版本
  • Linux x86_64
  • 高速本地 NVMe(不推荐使用网络存储)

对于在 FAISS 或专用向量数据库(如 Milvus 或 Pinecone)之间做评估的团队来说,其核心运维理念是相同的:同一平台、同一 ATO、同一运维模型,在已有 Elasticsearch 集群上叠加 GPU 加速的 ingest 能力。更广泛的 Elastic 与 NVIDIA 合作背景可参考 Elastic 和 NVIDIA 一起开启下一代企业 AI 搜索

从 Pattern A 开始,在单个 GPU 节点上验证你的语料库吞吐性能。当你对结果有信心后,再切换到 Pattern B,并使用上面的 ILM 策略,按查询 SLA 扩展 CPU 热服务层,并让 GPU ingest 层专注做它唯一擅长的事情:以比 CPU 快 12 倍的速度构建 HNSW 图。

关于 cuVS benchmark 方法与结果,参考 在 Elasticsearch 中使用 NVIDIA cuVS 实现向量索引最高可提升 12 倍速度。关于 Elastic 与 NVIDIA 更广泛的合作,参考 在大规模企业 AI 场景中提供动力:Elastic 与 NVIDIA cuVS 的集成

常见问题

为什么 Elasticsearch 在大规模语料上向量索引很慢?

HNSW 图构建是 CPU 受限的,并且在规模化时占据主要索引时间。加入 NVIDIA cuVS 插件后,图构建被迁移到 GPU,在 benchmark 硬件上可以提升最高 12 倍速度。对于数亿级向量语料,索引时间可以从"周级"下降到"天级"。

如何在不让 GPU 节点承担查询的情况下部署 Elasticsearch GPU 向量索引?

使用双层架构:GPU ingest 节点安装 cuVS 插件并配备 64 GB RAM,负责构建 HNSW segment 并持有活跃写 shard。随后通过 ILM rollover 将完成的 shard 迁移到 CPU 热服务层(192 GB RAM),该层负责所有查询。自定义节点属性 tier_function 用于控制新写入与迁移 shard 的分配。

Elasticsearch 的 dense_vector 字段是否可以使用 NVIDIA cuVS 进行 GPU 加速?

可以,在自管 Enterprise Elasticsearch 9.3 及以上版本中,且节点安装 cuVS 插件并配备支持的 NVIDIA GPU 时可以使用。但必须在 dense_vector mapping 中显式设置 index_options.type 为 int8_hnsw 或 hnsw,因为 9.1 及以上默认的 bbq_hnsw 不支持 GPU 加速。

GPU 向量索引节点在 Elasticsearch 中需要多少 RAM?

GPU ingest 节点只需要保存当前正在写入的 shard,因此总计约 60 GB 即可(32 GB JVM heap、10 GB CUDA 运行时与 pinned PCIe buffers、10--15 GB page cache、5 GB OS),与 AWS g6.4xlarge benchmark 一致。CPU 热服务节点由于需要保存累积 HNSW 语料,因此需要 128--192 GB RAM(取决于每节点 shard 数)。

为什么即使安装了 cuVS,我的 Elasticsearch GPU 插件仍然没有加速向量索引?

最常见原因是使用了默认的 bbq_hnsw 索引选项,而该选项不被 cuVS 插件支持。需要在 dense_vector mapping 中设置 index_options.type 为 int8_hnsw 或 hnsw。同时需要确认 GPU compute capability ≥ 8.0,CUDA 12.x,并且 vectors.indexing.use_gpu 设置为 true。

如何配置 ILM,使 shard 从 GPU 构建层迁移到 CPU 服务层?

在 warm 阶段设置 "migrate": {"enabled": false},避免 ILM 尝试迁移到不存在 data_warm 角色的节点,然后使用显式 allocate 动作将 shard 路由到 node.attr.tier_function: cpu_serve 的节点。完整策略结构和 index template 在文中给出。

我应该选择 Elasticsearch + NVIDIA cuVS 还是专用向量数据库?

如果你已经在使用 Elasticsearch 做搜索、可观测性或安全能力,那么加入 cuVS 可以在同一平台上支持 agentic AI 工作负载,而无需额外的数据存储或运维体系。同时 cuVS 完全可以在本地硬件运行,这对于无法使用托管向量数据库的 air-gapped、主权云或本地部署环境非常重要。

原文:https://www.elastic.co/search-labs/blog/nvidia-cuvs-elasticsearch-gpu-vector-indexing

相关推荐
鹧鸪云光伏5 小时前
光伏设计软件:多屋脊房型如何设计?
大数据·信息可视化·光伏·光伏设计·光伏图纸
产业家5 小时前
“国标”发布,AI终端硬件要“考级“了
人工智能
前沿推行者5 小时前
辽宁传媒学院教学特色解析:从实践导向到产教融合
大数据·人工智能
绝知此事5 小时前
2026 AI 技术生态全景指南:从 LLM 到 Agent,从 MCP 到 A2A
人工智能·ai·ai编程
AI算法沐枫5 小时前
大模型 | 大模型之机器学习基本理论
人工智能·python·神经网络·学习·算法·机器学习·计算机视觉
li星野5 小时前
Transformer 核心模块详解:多头注意力、前馈网络与词嵌入
人工智能·深度学习·transformer
灰灰勇闯IT5 小时前
catlass:昇腾NPU上的算子模板库
人工智能
桜吹雪5 小时前
所有智能体架构(2):ReAct(推理 + 行动)
人工智能
埃菲尔铁塔_CV算法5 小时前
YOLO11 与传统纹理特征融合目标检测 完整实现教程
人工智能·神经网络·yolo·计算机视觉