在 Redis,我们很快。为了展示我们的速度,我们使用我们新的 Redis 查询引擎(现已面向 Redis 软件正式发布)对市场上顶级的向量数据库提供商进行了基准测试。此功能增强了我们的引擎,使其能够并发访问索引,从而提高 Redis 查询、搜索和向量数据库工作负载的吞吐量。这篇博文展示了我们的基准测试结果,解释了提高查询吞吐量的挑战,以及我们如何通过新的 Redis 查询引擎克服这些挑战。这篇博文分为三个主要部分
让我们从最重要的部分开始,Redis 的速度有多快。
除了摄取和索引创建时间外,我们在 7 个向量数据库参与者中对两个关键指标进行了基准测试:吞吐量和延迟(请参见下面有关指标和原则的详细信息)。吞吐量表示系统在短时间内处理大量查询或大型数据集的能力,而延迟衡量个别相似性搜索返回结果的速度。
为了确保我们涵盖了这两方面,我们进行了两个基准测试,一个多客户端基准测试侧重于吞吐量,另一个单客户端和负载(多客户端)基准测试侧重于延迟。所有结果可以在下面的图表中进行过滤,所有关于我们如何进行测试的详细信息都可以在博客中找到。对于 Redis 来说,优先考虑吞吐量和延迟符合我们提供卓越速度和可靠性的核心理念。
我们的测试表明,与我们测试的任何其他向量数据库相比,Redis 在向量数据库工作负载方面更快,召回率 >= 0.98。对于低维数据集(deep-image-96-angular),Redis 的吞吐量比排名第二的数据库高 62%,对于高维数据集(dbpedia-openai-1M-angular),Redis 的吞吐量高出 21%。
注意事项:MongoDB 测试仅在使用较低的召回率级别时才为 gist-960-euclidean 数据集提供结果。此数据集的结果考虑了 0.82 到 0.98 之间的召回率结果的中位数。对于所有其他数据集,我们正在考虑召回率 >=0.98
Redis 在查询吞吐量和延迟时间方面优于其他纯粹的向量数据库提供商。
查询:对于相同的召回率水平,Redis 的每秒查询数 (QPS) 比 Qdrant 高出 3.4 倍,比 Milvus 高出 3.3 倍,比 Weaviate 高出 1.7 倍。在延迟方面,这里被认为是多客户端测试的平均响应,Redis 的延迟比 Qdrant 低 4 倍,比 Milvus 低 4.67 倍,比 Weaviate 快 1.71 倍,召回率水平相同。在延迟方面,这里被认为是在负载下(多客户端)的平均响应,Redis 的延迟比 Qdrant 低 4 倍,比 Milvus 低 4.67 倍,比 Weaviate 快 1.71 倍。
摄取和索引:由于其多段索引设计,Qdrant 是最快的,但 Redis 在快速查询方面表现出色。Redis 的索引时间比 Milvus 低 2.8 倍,比 Weaviate 低 3.2 倍。
本节提供了 Redis 7.4 与其他行业提供商(例如 Milvus 2.4.1、Qdrant 1.7.4 和 Weaviate 1.25.1)的全面比较,这些提供商专门提供向量功能。
在下面的图表中,您可以分析所有结果,包括 RPS(每秒请求)、延迟(单客户端和多客户端,在负载下)、P95 延迟和索引时间。所有结果都在不同选定的数据集中进行测量。
在单客户端基准测试中,有一些情况是 Redis 和竞争对手的性能处于相同水平。Weaviate 和 Milvus 在云设置中展示了运行问题;在附录中对这些发现进行了全面描述。
在对支持向量相似性的通用数据库的查询性能进行基准测试时,Redis 显著优于竞争对手。
查询:对于相同的召回率,Redis 的每秒查询数 (QPS) 比 Amazon Aurora PostgreSQL v16.1 with pgvector 0.5.1 高 9.5 倍,延迟低 9.7 倍。与使用 Atlas Search 的 MongoDB Atlas v7.0.8 相比,Redis 的 QPS 高出 11 倍,延迟低 14.2 倍。与 Amazon OpenSearch 相比,Redis 的 QPS 高出 53 倍,延迟低 53 倍。
摄取和索引:与使用 pgvector 0.5.1 的 Amazon Aurora PostgreSQL v16.1 相比,Redis 具有显著优势,索引时间低 5.5 到 19 倍。
本节对 Redis 7.4 与使用 pgvector 0.5.1 的 Amazon Aurora PostgreSQL v16.1 以及使用 Atlas Search 的 MongoDB Atlas v7.0.8 和 Amazon OpenSearch 2.11 进行的全面比较,提供了有关通用数据库云环境中向量相似性搜索性能的宝贵见解。
在下面的图表中,您可以分析所有结果,包括 RPS(每秒请求)、延迟(单客户端和多客户端,在负载下)、P95 延迟和索引时间。所有结果都在不同选定的数据集中进行测量。
除了上面展示的性能优势外,一些通用数据库还存在与缺乏精度和索引配置可能性相关的向量搜索限制,在附录中进行了全面描述。
与其他 Redis 模仿者(例如 Amazon MemoryDB 和 Google Cloud MemoryStore for Redis)相比,Redis 展示了显著的性能优势。这表明 Redis 及其企业实现针对性能进行了优化,超过了其他复制了 Redis 的提供商。
查询:与 Amazon MemoryDB 相比,对于相同的召回率,Redis 的每秒查询数 (QPS) 高 3.9 倍,延迟低 4.1 倍。与 GCP MemoryStore for Redis v7.2 相比,Redis 的 QPS 高 2.5 倍,延迟低 4.8 倍。
摄取和索引:Redis 比 Amazon MemoryDB 具有优势,索引时间低 1.39 到 3.89 倍。与 GCP MemoryStore for Redis v7.2 相比,Redis 的索引优势更加明显,索引时间低 4.9 到 10.34 倍。
在下面的图表中,您可以分析所有结果,包括:RPS(每秒请求)、延迟(单客户端和多客户端,在负载下)、P95 延迟和索引时间。所有结果都在不同选定的数据集中进行测量。
为了实现上面展示的结果,我们引入了一种新的增强功能,使查询能够并发访问索引。本节详细介绍了这些增强功能以及我们的工程团队如何克服这些挑战。
Redis 具有 经过验证的单线程 架构,我们一直在寻求改进,使 Redis 更上一层楼。为此,我们需要克服现有设计的几个限制。首先,Redis 的扩展方式(读写命令,Redis 操作)基于以下假设:大多数命令都很短,通常每个命令的复杂度为 O(1),并且彼此独立。因此,将数据与 Redis 集群划分成独立的 Redis 分片(或扩展)会导致将多个请求扩展到多个分片,因此我们获得了即时的负载平衡,并将命令均匀地分布在分片之间。对于所有具有高度表达能力的 Redis 查询(多个查询项和条件)或涉及任何数据操作(排序、分组、转换)来说,情况并非如此。其次,单个线程上的长时间运行查询会导致阻塞,增加整体命令延迟,并降低 Redis 服务器的整体吞吐量。例如,利用倒排索引在数据中进行搜索就是这类长时间运行的查询。
搜索命令并非 O(1) 时间复杂度的命令。搜索通常会结合多个索引扫描来满足多个查询谓词。这些扫描通常以对数时间复杂度 O(log(n)) 进行,其中 n 是索引映射的数据点数量。拥有多个这样的扫描,组合其结果并聚合它们,在计算方面比典型的 Redis GET、SET、HSET 等操作要重得多。这与我们关于命令简单且运行时间短的假设相矛盾。
使用亚线性时间复杂度的扩展并不能帮助降低单个客户端延迟,而降低单个客户端延迟是提高单线程架构中吞吐量的必要条件。即使分片可以将数据分布到多个 Redis 进程(和节点),随着分片的增加(以及 Redis 进程的增加),总查询时间并没有明显减少。我们有两个原因来解释这一点。
例如,即使使用最先进的算法,搜索类似向量在今天仍然是计算密集型的,因为它将查询向量与索引提供的每个候选向量进行比较。这种比较不是 O(1) 比较,而是 O(d),其中 d 是向量维度。简单来说,每次计算都在比较两个完整的向量。这在计算上很密集。当在主线程上运行时,这会导致 Redis 主线程比常规 Redis 工作负载甚至其他搜索情况占用更长时间。
高效地扩展搜索需要结合水平扩展(扩展出去)和垂直扩展(扩展上去),在访问索引时实现并发性。下图说明了单个分片的架构。
多个查询正在执行,每个查询都在单独的线程上执行。我们采用了简单但著名的 生产者-消费者模式。1. 查询上下文(规划)在主线程上准备并在共享队列上排队。2. 从这里,线程消费队列并并发地执行查询管道,与其他线程并发。这使我们能够在保持主线程处于活动状态以处理更多传入请求(例如其他 Redis 命令或准备和排队其他查询)的同时执行多个并发查询。3. 完成后,查询结果将发送回主线程。
为了对我们的 Redis 查询引擎进行基准测试,我们测试了 Redis 的全文本搜索和向量搜索查询。特别是对于向量搜索,我们选择了 gist-960 数据集,其中包含 100 万个向量,每个向量具有 960 维度,并将旧的单分片设置与使用 6、12 和 24 线程配置的新设置进行了比较,同时改变了 M(每个节点的最大连接数)和 EF(HNSW 索引在搜索期间动态候选列表的大小)配置。
性能改进是一致的,表明对于查询吞吐量每提高 2 倍,就需要将线程增加 3 倍,这表明所有配置都能够有效地利用资源。我们测试了 FLAT(暴力破解)算法和 HNSW 扩展,我们的测试证实,垂直扩展加速比(添加的资源提高可实现吞吐量的效率)对于应用于两种算法的每个扩展因子都是一样的。下图说明了向量工作负载的可扩展因子。
根据这些发现,我们引入了“扩展因子”的概念,这是一个比率,可以通过激活额外的线程和 vCPU 来显着提高查询吞吐量,从而提高性能。将结果扩展到全文本搜索用例后,我们可以确认理论扩展因子与经验结果非常吻合。
我们继续改进 Redis 查询引擎。有时,最好不要等待后台线程来处理任务,而是直接在主线程上执行查询。对于短小简单的查询,情况似乎就是这样。访问键空间仍然是一个瓶颈,因为它需要锁定主线程,而索引拥有自己的优化数据结构,这些数据结构位于键空间之外。有时,当查询明确请求从键空间加载数据、投影数据(`RETURN` 或 `LOAD`)时,我们需要符合 Redis 并锁定键空间(Redis 锁机制)。这也可能有所改进。
本节包含有关设置、我们如何进行测试以及数据集和工具选择背后的原因的所有详细信息。让我们从我们的基准测试原则开始。
为了确保基准测试是有意义且可操作的,我们认为一个好的基准测试应该遵循以下原则。
通过坚持这些原则,我们努力确保我们的基准测试在与其他解决方案进行比较时提供有价值的见解,推动我们查询引擎的持续改进,并坚持 Redis 提供卓越性能的承诺。
我们将 Redis 与三组进行了比较:纯向量数据库提供商、具有向量功能的通用数据库以及云服务提供商的 Redis 模仿者。
我们将 Redis 与三类向量数据提供商进行了比较:纯向量数据库提供商、具有向量功能的通用数据库以及其他 Redis 模仿者云服务提供商。我们发现,这三组的速度、可扩展性和企业功能差异很大。纯向量数据库在性能方面表现更好,但在扩展性方面表现更差。通用数据库在性能方面差得多,但在其他集成方面表现更好。Redis 模仿者速度明显更慢,没有最新的速度改进。许多用户认为 Redis 模仿者同样快,但我们希望打破这种幻觉,为您节省时间和金钱,通过将它们与 Redis 进行比较。
我们的主要发现总结如下
纯玩 | 通用目的 | Redis 模仿者提供商 | |
提供商 | Qdrant、Weaviate、Milvus | Amazon Aurora(PostgreSQL w/ pgvector)、MongoDB、Amazon OpenSearch | Amazon MemoryDB、Google Cloud MemoryStore for Redis |
缺失的提供商 | Pinecone* | Couchbase*、ElasticSearch* | |
发现总结 | 纯玩家声称他们专为特定目的而构建,但通常缺乏企业功能和稳定性 | 完善的通用数据库确实具有这些企业功能,但缺乏性能 | 如果您了解 Redis 是您的解决方案,请考虑模仿者不如 Redis 性能好 |
我们根据客户的反馈选择了这些提供商,他们希望看到我们如何与他们竞争,以及他们在 DB Engine 上的受欢迎程度。
* 我们还想分析 ElasticSearch、Pinecone 和 Couchbase,但是,这些数据库提供商在其服务条款中加入了 DeWitt 条款,该条款在法律上限制了任何形式的基准测试。具体来说,该条款不仅禁止发布基准测试结果,还禁止实际对他们的产品进行任何性能评估。因此,ElasticSearch、Pinecone 和 Couchbase 客户无法洞察他们的潜在性能或有效性,这些性能或有效性可以独立验证。
我们在云服务解决方案中使用相同的硬件测试了竞争对手的客户端和服务器端。配置参数被定义为平均分配相同数量的 vCPU 和内存。附录中的表格总结了每个测试解决方案的资源类型。
重要的是要强调,我们付出了额外的努力来确保所有竞争对手都具有稳定的结果,这些结果与其他基准测试数据来源相匹配。例如,Qdrant 从我们的基准测试中获得的云结果与 Qdrant 发布的结果相比,表明我们的测试要么与他们发布的结果相等,要么有时甚至更好。这使我们对现在分享的数据更有信心。下图显示了我们的 Qdrant 测试与他们自述的结果相比的结果。
我们简化了玩家的配置设置,以确保比较公平。因此,我们将基准测试结果比较了单节点和纯最近邻 (k-NN) 查询。该基准测试评估了不同引擎在相同资源限制下的性能,并显示了相对性能指标。
这些指标包括摄取和索引时间,以及单节点上的查询性能(吞吐量和延迟),以及不同向量维数和距离函数的不同数据集。特别是对于查询性能,我们分析了以下两个方面:
我们的测试深入研究了各种性能指标,全面展示了 Redis 在向量数据库领域中的地位。这些测试使用两个主要操作进行:
对于所有基准测试解决方案,我们将 M 的值设为 16、32 和 64 个出边,并将 EF 的值设为 64、128、256 和 512,用于构建和运行时变化。为了确保结果可重复,每个配置都运行了 3 次,并选择了最佳结果。有关 HNSW 配置参数和查询的更多信息,请阅读更多内容。
精度测量通过比较返回的结果与之前为每个查询计算的真实值(作为每个数据集的一部分提供)的准确性来完成。
我们专注于分别测量摄取和查询性能。这种方法允许获得清晰、精确的洞察,并使我们能够更轻松地将我们的结果与其他竞争对手的基准测试进行比较,竞争对手通常也会独立测试插入和查询。我们计划在后续文章中讨论包含更新、删除和定期搜索的混合工作负载,以提供全面的视图。
鉴于不同基准测试解决方案之间过滤支持的水平不同,我们目前没有深入研究过滤搜索基准测试的复杂性。过滤增加了一层显著的复杂性,并且每个解决方案的处理方式都不同。我们在这里不会深入研究。
此外,我们正在积极扩展[请参阅此处的 PR]基准测试实用程序,以涵盖每个解决方案的内存使用情况细分(对于任何与 Redis 兼容的解决方案,都已经有一个可用的示例),以及允许对数十亿个向量进行基准测试。
我们选择了以下数据集来涵盖各种维度和距离函数。这种方法确保我们可以为各种用例提供有价值的见解,从简单的图像检索到大型 AI 应用程序中复杂的文本嵌入。
数据集 | 向量数量 | 向量维度 | 距离函数 | 描述 |
gist-960-euclidean | 1,000,000 | 960 | 欧几里德 | 使用Texmex数据集和胃肠道间质瘤 (GIST) 算法生成图像特征向量。 |
glove-100-angular | 1,183,514 | 100 | 余弦 | 通过将 GloVe 算法应用于来自互联网的文本数据来生成词向量。 |
deep-image-96-angular | 9,990,000 | 96 | 余弦 | 从 ImageNet 训练数据集的 GoogLeNet 神经网络输出层提取的向量。 |
dbpedia-openai-1M-angular | 1,000,000 | 1536 | 余弦 | OpenAI 的 DBpedia 实体文本嵌入数据集,使用 text-embedding-ada-002 模型。 |
我们的基准测试是使用 Amazon Web Services 实例上的客户端完成的,这些实例通过我们的基准测试基础设施进行配置。每个设置都包含 Vector DB 部署和客户端 VM。基准测试客户端 VM 是一个 c6i.8xlarge 实例,具有 32 个 VCPU 和 10 Gbps 网络带宽,以避免任何客户端瓶颈。基准测试客户端和数据库解决方案置于最佳网络条件下(同一区域),实现了稳定的低延迟和稳定的网络性能,这对稳态分析必不可少。
我们还在网络、内存、CPU 和 I/O 上运行了基线基准测试,以了解潜在的网络和虚拟机特性(如果适用)。在整个基准测试集中,网络性能保持在测量的限制以下,包括带宽和 PPS,以产生稳定、稳定的超低延迟网络传输(每个数据包的 p99 小于 100 微秒)。
对于这篇博文中展示的基准测试结果,我们使用了Qdrant 的 vector-db-benchmark 工具,主要是因为它维护良好,并接受来自多个供应商(Redis、Qdrant、Weaviate 等)的贡献,促进了结果的可重复性。
此外,它允许进行多客户端基准测试,并且可以轻松扩展以包含更多供应商和数据集。
每个设置的详细配置可以在我们的基准测试仓库中找到以供评估。您可以按照这些步骤来重现这些基准测试。
您可以亲身体验新的 Redis 查询引擎提供的更快搜索和向量数据库。它现在在 Redis 软件中普遍可用,并将于今年晚些时候发布到 Redis Cloud。要立即为您的应用程序获得更快的搜索速度,请下载 Redis 软件,并联系您的代表,以获得 16 倍的性能提升。
解决方案 | 设置类型(软件或云) | 版本 | 设置 | 特殊调整 |
Redis | Redis Cloud | 7.4 | 具有底层 AWS m6i.2xlarge(8 个核心和 32GB 内存)的 Redis Cloud | 缩放因子设置为 4(6x vCPU) |
Qdrant | Qdrant Cloud | 1.7.4 | Qdrant Cloud (8 个核心和 32GB 内存) | 目标为更高 qps 或更低延迟的不同段数量 |
Weaviate | 软件 | 1.25.1 | **其云上的操作问题。使用软件** m6i.2xlarge(8 个核心和 32GB 内存) | |
Milvus | 软件 | 2.4.1 | **其云上的操作问题。使用软件** m6i.2xlarge(8 个核心和 32GB 内存) | |
Amazon Aurora | AWS 云 | PostgreSQL v16.1 和 pgvector 0.5.1 | db.r7g.2xlarge(8 个核心和 64GB 内存) | 我们测试了“Aurora 内存优化”和“Aurora 读取优化”实例。 |
MongoDB | MongoDB Atlas 搜索 | MongoDB v7.0.8 | M50 通用用途部署(8 个核心和 32GB 内存) | 我们使用了 1 的写入关注度,以及对主机的读取偏好。 |
Amazon OpenSearch | AWS 云 | OpenSearch 2.11(lucene 9.7.0) | r6g.2xlarge.search(8 个核心和 64GB 内存) | 我们测试了 OpenSearch 默认的 5 个主分片设置和单分片设置。5 个分片设置被证明是 OpenSearch 结果的最佳设置。 |
Amazon MemoryDB | AWS 云 | 7.1 | db.r7g.2xlarge(8 个核心和 53GB 内存) | |
用于 Redis 的 GCP MemoryStore | Google 云 | 7.2.4 | 标准层大小为 36 GB |
Weaviate 和 Milvus 在云设置上展示了操作问题,这些问题应该专门针对给定的数据集。具体来说
鉴于上述问题,我们决定部署 Milvus 和 Weaviate 的基于软件的解决方案,提供与其他玩家相同的 CPU 和内存资源,即 8 个 VCPU 和 32GB 内存。
鉴于 Qdrant 索引结果,我们决定了解多个段对索引和查询性能的影响,并确认这是一个权衡。减少 Qdrant 的段数量会导致更高的搜索 qps,但会降低精度并导致更高的索引时间。如上所述,这是一个权衡。我们调整了 Qdrant 的段数量以达到最小值 (2),并注意到召回率确实降低了,但查询时的 qps 改善不足以达到 Redis 的水平,使 Redis 在 KNN 搜索方面保持巨大优势。
具体来说,对于我们运行的基准测试,读取优化实例并没有优于内存优化实例。这是因为整个数据集都适合在 PostgresSQL 的内存中,并且它得到了Amazon 公告的支持。
本地 NVMe 只会缓存被驱逐的未修改页面,因此,如果您的向量数据频繁更新,您可能不会看到相同的加速。此外,如果您的向量工作负载完全适合内存,您可能不需要优化读取实例 - 但运行一个实例将有助于您的工作负载在相同的实例大小上继续扩展。
目前,MongoDB Atlas 向量搜索不提供在创建索引期间配置 EF_CONSTRUCT 和 M 的方法,并且唯一可以提高精度的可配置选项是在运行时通过 numCandidates 配置(即 EF_RUNTIME)公开。这种设计选择简化了用户体验,但限制了定制和对需要更高精度的用例的回复质量。即使遵循 Mongo 的官方文档
我们建议您指定一个比要返回的文档数量(限制)更大的数字以提高准确性,尽管这可能会影响延迟。例如,我们建议对于仅一个文档的限制,使用十到二十个最近邻居的比率。
并使用一个numCandidates配置,该配置达到预期回复限制的 20 倍(这意味着我们的最大 EF_RUNTIME 为 2000),MongoDB 解决方案的精度远非最佳,没有超过 0.82。
关于纵向和横向扩展方法的说明:本文档展示了多个从纵向扩展中受益的用例。但是,需要注意的是,某些用例可能无法有效地扩展。为了确保更平滑的扩展过程,我们将把纵向扩展反模式记录在 Redis 文档中,并且 Redis 专家将帮助客户了解纵向扩展是否会提升其用例的性能,并指导他们在是否使用纵向扩展和横向扩展方面。