工程

向量搜索:HotKV 对比 Redis 8 向量集合,从 1 到 100 个客户端

HotKV 与 Redis 8.10.2 在 100,000 和 999,000 个嵌入向量上的向量搜索,1 到 100 个客户端:吞吐量、延迟、召回率、加载速度、内存与局限。

HotKV 向量搜索:吞吐量与召回率,以相互连接的近邻节点示意。

许多 AI 功能都以向量搜索为基础:RAG 检索、语义缓存、智能体记忆。Redis 8 在服务器中内置了向量集合(目前为测试版数据类型),因此它是显而易见的对比对象。我们将相同的 OpenAI 嵌入向量分别加载到 HotKV 和 Redis 8.10.2 中,以 1 到 100 个并发客户端连接对两者运行相同的 1,000 条查询,并测量了答案的准确度、每个引擎每秒处理的查询数,以及每条查询的耗时。

简而言之:在 999,000 个向量上、召回率不低于 95% 时,HotKV 的每秒查询数在 1 个客户端时是 Redis 的 1.4 倍,在 100 个客户端时是 7.9 倍(51,146 对比 6,510)。在 99% 召回率下,这两个比值分别为 1.8 和 5.4。在每种客户端数下,HotKV 的延迟中位数都更低。Redis 的吞吐量到 32 个客户端时已趋于平稳,而 HotKV 的吞吐量一直增长到 100 个客户端。HotKV 加载向量的速度快约 5 倍,并且在每个搜索深度上召回率都更高。这只是一台机器上的一个数据集,所用的 HotKV 是尚未发布的开发构建,我们也没有测量 Redis 的 Query Engine 或其 8 位模式,因此请将其视为一次测量,而不是排名。

测试内容

数据

Kumar Shivendu 和 Nirant Kasliwal 发布的 dbpedia-entities-openai-1M(MIT 许可)的前 999,000 行,以及用于较小索引的前 100,000 行。这些行是用 OpenAI text-embedding-ada-002 嵌入的 DBpedia 实体,维度为 1,536。最后 1,000 行用作查询,因此没有任何一行同时出现在两个集合中。标准答案是每条查询精确的前 10 个最近邻,以 64 位浮点数暴力计算得出,独立于两个引擎,因此两者都以相同的真值作为评分依据。

引擎与设置

  • 引擎:HotKV 提交 c8dafd37(VSIM.CREATEINDEX、VSIM.SET、VSIM.SEARCH),这是一个尚未发布的开发构建,使用默认的发布编译选项编译,而非 -march=native。Redis 8.10.2 从其发布标签以标准 make 构建(VADD、VSIM)。两者构建的都是 HNSW 图。
  • 索引设置:两者均使用余弦相似度,以及 M=16、ef_construction=200 的 HNSW,并且都是显式设置。这些同时也是两个引擎各自的默认值。
  • 精度:两者都使用全精度 float32 向量。Redis 默认使用 8 位量化,因此它以 NOQUANT 运行。
  • 机器:一台 Azure Standard_D160alds_v7(AMD EPYC 9V45,160 个 vCPU)。两个服务器都绑定到同样的 128 个 vCPU 上,负载生成器绑定到其余 32 个上,全部通过本地回环通信。HotKV 运行 128 个线程,Redis 使用其默认的 I/O 线程设置;我们试过 1、4、8 和 16,该设置并未带来一致的差异。
  • 负载生成器:每个客户端连接一个进程,每个进程同时只保持一个未完成的请求,请求在计时部分开始前就已构建好。在任何一次运行中,最繁忙的负载生成器进程占用的也只是一个 CPU 的 8%,因此客户端从未成为限制因素。

测试流程

在搜索深度(ef)为 40、80、150 和 300 时(较大的索引还包括 500),我们分别以 1、2、4、8、16、32、50 和 100 个客户端反复运行这 1,000 条查询:先预热 1 秒,再计时 4 秒,每种组合各运行三次,两个引擎的顺序交替进行。我们报告中位数。召回率通过单个连接单独测量。每次运行中 HotKV 都通过 32 个连接加载。Redis 的索引只构建一次,通过 32 个连接使用 VADD ... CAS 构建,保存后在测量时加载。脚本和每次试验的结果都在基准测试仓库中。

结果

相同的召回率目标

两个引擎在相同的 ef 下达不到相同的召回率,因此我们在共同的最低召回率目标下比较吞吐量:对于每个目标,取能达到该目标的实测搜索深度中最快的那个。所用的深度和实际达到的召回率列在表中,因为两者略有不同。这里使用的是实测深度,而非插值。999,000 个向量上的每秒查询数:

Recall@10 目标客户端HotKVRedis 8.10.2HotKV 对比 Redis延迟中位数
不低于 95%11,328 (ef 80, 0.970)946 (ef 80, 0.962)1.40x0.77 / 1.07 ms
不低于 95%810,3425,5311.87x0.79 / 1.43 ms
不低于 95%1618,5007,2652.55x0.87 / 2.15 ms
不低于 95%5037,5086,8255.50x1.33 / 7.17 ms
不低于 95%10051,1466,5107.86x1.91 / 13.49 ms
不低于 99%1507 (ef 300, 0.993)287 (ef 500, 0.994)1.77x1.99 / 3.31 ms
不低于 99%166,9612,3223.00x2.30 / 6.70 ms
不低于 99%5012,3932,4834.99x4.02 / 18.91 ms
不低于 99%10013,8432,5835.36x7.11 / 37.65 ms

延迟中位数一栏为 HotKV / Redis。以 90% 为目标时规律相同:100 个客户端时每秒查询数为 90,003 对比 7,973(11.3 倍),两者都在 ef 40。

各搜索深度

efHotKV 召回率Redis 召回率HotKV,1 个客户端Redis,1 个客户端HotKV,50 个客户端Redis,50 个客户端HotKV,100 个客户端Redis,100 个客户端
400.9400.9232,1081,25963,8978,06190,0037,973
800.9700.9621,32894637,5086,82551,1466,510
1500.9870.98087563621,9125,24126,1224,942
3000.9930.99050739612,3933,45413,8433,402
5000.9970.9943382877,6882,4838,8432,583

以上为 999,000 个向量上的每秒查询数。在 100,000 个向量上规律相同。在 95% 召回率下,HotKV 的每秒查询数在 1 个客户端时是 Redis 的 1.5 倍(1,816 对比 1,214),在 100 个客户端时是 8.9 倍(63,247 对比 7,119)。

其中有多少是噪声

每个单元格都是三次试验的中位数。一半单元格的最低与最高试验结果之差不超过中位数的 1.3%,十分之九的单元格不超过 7%,差距最大的为 26%(Redis,100,000 个向量,ef 300,50 个客户端)。报告列出了每一次试验。

召回率在每次索引构建后测量一次。每个引擎在 100,000 个向量上的三次独立构建,在相同深度下最多相差 0.013,因此在较小的索引上,HotKV 更高的召回率在 ef 300 及以下是明确的,而在 ef 500 时则处于不同构建之间的波动范围内。

加载与内存

在各使用 32 个连接加载时,HotKV 加载 999,000 个向量用时 188 秒(每秒 5,325 个),Redis 用时 935 秒(每秒 1,069 个),其中包括负载生成器格式化每个向量所花的时间。在 100,000 个向量上,用时为 15 秒对比 57 秒。在一项针对 20,000 个向量的检查中,Redis 使用 CAS 时比不使用时加载更快(每秒 2,279 个对比 1,488 个向量),因此我们采用了它。 Redis 的加载在更早的一个步骤中进行,当时 Redis 被固定在 4 个 vCPU 上,同时机器上还在运行其他检查;HotKV 则在 128 个 vCPU 上单独加载。因此 Redis 的加载时间是其速度的下限,而不是同等条件下的对比。

加载 999,000 个向量后,HotKV 进程占用 6.77 GB,Redis 进程占用 7.01 GB。

此处限制 Redis 8.10.2 的因素

Redis 向量集合在各自独立的线程上执行每次搜索,但 HNSW 代码的线程槽位数是固定的(32 个,在编译 Redis 时设定),并且向量是在主线程上添加的。在我们的运行中,从 32 个客户端起,Redis 让机器上 6 到 30 个 vCPU 处于忙碌状态,其吞吐量已趋于平稳。在 ef 80、100 个客户端时,HotKV 让约 92 个 vCPU 处于忙碌状态,而且吞吐量仍在增长。这是每个引擎在这台机器上的自身表现,而非基准测试所做的配置。

局限性

以上是 HotKV Ltd 对上述版本和配置的测量结果,并不代表对所有 Redis 部署的结论。

测试环境

  • 开发构建:提交 c8dafd37 是开发构建,而非发布版本。
  • 一个数据集,一台机器:1,536 维的 OpenAI 嵌入向量,仅取前 10 个,float32,余弦。其他维度、数据或硬件可能得出不同的比值。
  • 客户端与服务器共用机器:负载生成器运行在独立的 vCPU 上,但与服务器共享内存系统和末级缓存。
  • 关闭持久化:两个服务器都没有写入快照或仅追加文件。

未测量的内容

  • Redis 的 8 位模式:Redis 默认存储 8 位量化向量,占用的内存更少。我们比较的是 float32 对 float32。
  • Redis Query Engine:Redis 还通过 FT.CREATE 和 FT.SEARCH 提供向量搜索。我们只测试了向量集合,因此这些结果无法说明 Query Engine 的情况。
  • Redis 加载与重新加载:Redis 的索引在较早的一次运行中构建,当时 Redis 被固定在 4 个 vCPU 上,随后保存并在测量时重新加载,因此 Redis 的加载时间只是下限,不能与 HotKV 同等条件比较。在一次对 20,000 个向量的检查中,在重新加载的索引上搜索比在新建索引上慢约 10%,所以 Redis 的查询数据可能也偏低约这么多。

亲自试一试

向量搜索与 HotKV 的提示词缓存内置在同一个服务器中,同一个向量索引也支撑着它的语义缓存和智能体记忆。HotKV Cloud 的每个套餐都包含向量搜索。提示词缓存、语义缓存和智能体记忆随 Performance 及以上套餐提供。在 HotKV Cloud 上开始使用,或联系销售,用您自己的嵌入向量对它进行基准测试。

觉得有用?

分享这篇文章

继续讨论

评论

对方法有疑问?在您的硬件上得到了不同的结果?欢迎分享您的发现。评论经审核后才会显示。

发表评论

您的显示名称和评论在审核通过后会公开。您的电子邮件地址仅用于上述通知,绝不会显示。您开始输入后,Cloudflare Turnstile 会进行反垃圾检查。 隐私详情.