今天,我们很高兴宣布 RedisGraph v1.0 正式发布。RedisGraph 是 Redis 开发的一个 Redis 模块,旨在为 Redis 添加 图数据库 功能。六个月前,我们在预览/测试版模式下发布了 RedisGraph,感谢社区和客户在 GA 版本开发过程中提供的宝贵反馈和建议。
与现有图数据库实现不同,RedisGraph 将连接数据表示为 邻接矩阵 而不是每个数据点的 邻接列表。通过将数据表示为稀疏矩阵并利用 GraphBLAS(一个针对稀疏矩阵操作的高度优化的库)的强大功能,RedisGraph 提供了一种快速高效的方式来存储、管理和处理图。事实上,我们的初步基准测试已经发现 RedisGraph 比现有图数据库快 6 到 600 倍!下面,我将分享我们如何对 RedisGraph v1.0 进行基准测试,但如果您想了解更多关于我们如何使用稀疏矩阵的信息,请查看以下链接。
在进入我们的基准测试之前,我应该指出,Redis 默认情况下是一个单线程进程。在 RedisGraph 1.0 中,我们没有发布将图划分为多个分片的功能,因为将所有数据放在一个分片中可以让我们执行更快的查询,同时避免分片之间的网络开销。RedisGraph 绑定到 Redis 的单线程以支持所有传入查询,并包含一个线程池,该线程池在模块加载时获取可配置数量的线程以处理更高的吞吐量。每个图查询都由主 Redis 线程接收,但在线程池的其中一个线程中计算。这使得读取可以轻松地扩展并处理大量的吞吐量。在任何给定时刻,每个查询都只在一个线程中运行。
这与其他图数据库实现不同,其他图数据库实现通常在机器的所有可用内核上执行每个查询。我们认为我们的方法更适合实时现实世界的用例,在这些用例中,高吞吐量和低延迟在并发操作下比一次处理一个序列化请求更重要。
虽然 RedisGraph 可以并发执行多个读取查询,但以任何方式修改图的写入查询(例如引入新节点或创建关系并更新属性)必须以完全隔离的方式执行。RedisGraph 使用读/写 (R/W) 锁来强制执行写/读分离,因此多个读取器可以获取锁,或者只有一个写入器可以获取锁。只要写入器正在执行,就没有人可以获取锁,只要读取器正在执行,写入器就无法获取锁。
现在我们已经有了重要的背景知识,让我们深入了解最新基准测试的细节。在图数据库领域,有多种基准测试工具可用。最全面的一个工具是 LDBC graphalytics,但对于此版本,我们选择了一个更简单的基准测试,该基准测试由 TigerGraph 于 2018 年 9 月 发布。它评估了领先的图数据库,如 TigerGraph、Neo4J、Amazon Neptune、JanusGraph 和 ArangoDB,并发布了所有平台上所有查询的平均执行时间和总运行时间。TigerGraph 基准测试涵盖以下内容
TigerGraph 基准测试报告 TigerGraph 比其他任何图数据库快 2-8000 倍,因此我们决定挑战这个 (有据可查的) 实验,并使用完全相同的设置比较 RedisGraph。由于 TigerGraph 比较了所有其他图数据库,因此我们使用其基准测试发布的结果,而不是重复这些测试。
鉴于 RedisGraph 是 v1.0,并且我们计划在未来的版本中添加更多功能和功能,对于我们当前的基准测试,我们决定主要关注 k 步邻域计数查询。当然,我们将在不久的将来发布其他查询的结果。
云实例类型 | vCPU | 内存 (GiB) | 网络 | SSD |
---|---|---|---|---|
AWS r4.8xlarge | 32 | 244 | 10 千兆位 | 仅 EBS |
名称 | 描述和来源 | 顶点 | 边 |
---|---|---|---|
graph500 | 合成 Kronecker 图 http://graph500.org |
240 万 | 6400 万 |
Twitter 用户-关注者有向图 http://an.kaist.ac.kr/traces/WWW2010.html | 4160 万 | 14.7 亿 |
k 步邻域查询是一种局部类型的图查询。它计算单个起始节点(种子)在特定深度连接到的节点数量,并且只计算距离 k 步远的节点。
以下是 Cypher 代码
MATCH (n:Node)-[*$k]->(m) where n.id=$root return count(m)
这里,$root 是我们开始探索图的种子节点的 ID,$k 表示我们计数邻居的深度。为了加快执行速度,我们使用了根节点 ID 的索引。
虽然我们遵循了与 TigerGraph 完全相同的基准测试,但我们惊讶地发现,他们只比较了单个请求查询响应时间。基准测试未能测试并发并行负载下的吞吐量和延迟,而这几乎代表了任何实时现实场景。正如我之前提到的,RedisGraph 从一开始就为极高的并行性而构建,每个查询都由一个单独的线程处理,该线程利用 GraphBLAS 库以线性代数处理矩阵运算。然后 RedisGraph 可以添加线程并以接近线性的方式扩展吞吐量。
为了测试这些并发操作的影响,我们在 TigerGraph 基准测试中添加了并行请求。即使 RedisGraph 只使用了一个核心,而其他图数据库使用多达 32 个核心,它也实现了比任何其他图数据库(除了在 Twitter 数据集上的单请求 k 步查询测试中 TigerGraph)更快的(有时快得多)响应时间。
单个请求基准测试基于 300 个种子进行一步和两步查询,以及 10 个种子进行三步和六步查询。这些种子在所有图数据库上按顺序执行。行 `时间 (毫秒)` 表示所有种子在给定数据集上每个数据库的平均响应时间。每个数据集的“规范化”行表示这些平均响应时间相对于 RedisGraph 的规范化结果。
需要注意的是,TigerGraph 对所有数据库上所有请求的一步和两步查询应用了三分钟的超时时间,对三步和六步查询应用了 2.5 小时的超时时间(请查看 TigerGraphs 的基准测试报告,了解每个数据库超时了多少请求)。如果给定数据集和给定数据库的所有请求都超时,我们将其结果标记为“N/A”。当存在平均时间时,这仅适用于成功执行的请求(种子),这意味着查询没有超时或生成内存不足异常。这有时会导致结果失真,因为某些数据库无法响应更难的查询,从而导致更好的平均单个请求时间,并对数据库的性能产生错误的印象。在所有测试中,RedisGraph 从未超时或生成内存不足异常。
数据集 | 度量 | RedisGraph | TigerGraph | Neo4j | Neptune | JanusGraph | ArangoDB |
---|---|---|---|---|---|---|---|
graph500 | 时间 (毫秒) | 0.39 | 6.3 | 21.0 | 13.5 | 27.2 | 91.9 |
规范化 | 1 | 16.2 | 53.8 | 34.6 | 69.7 | 235.6 | |
时间 (毫秒) | 0.8 | 24.1 | 205.0 | 289.2 | 394.8 | 1,674.7 | |
规范化 | 1 | 30.1 | 256.3 | 361.5 | 493.5 | 2,093.4 |
数据集 | 度量 | RedisGraph | TigerGraph | Neo4j | Neptune1 | JanusGraph | ArangoDB2 |
---|---|---|---|---|---|---|---|
graph500 | 时间 (毫秒) | 30.7 | 71 | 4,180.0 | 8,250.0 | 24,050.0 | 16,650.0 |
规范化 | 1 | 2.3 | 136.2 | 268.7 | 783.4 | 542.3 | |
时间 (毫秒) | 503.0 | 460.0 | 18,340.0 | 27,400.0 | 27,780.0 | 28,980.0 | |
规范化 | 1 | 0.9 | 36.5 | 54.5 | 55.2 | 57.6 |
数据集 | 度量 | RedisGraph | TigerGraph | Neo4j | Neptune1 | JanusGraph | ArangoDB*2 |
graph500 | 时间 (毫秒) | 229 | 410 | 51,380.0 | 2,270.0 | 1,846,710.0 | 3,461,340.0 |
规范化 | 1 | 1.8 | 224.4 | 9.9 | 8,064.2 | 15,115.0 | |
时间 (毫秒) | 9301 | 6730 | 298,000.0 | 38,700.0 | 4,324,000.0 | 3,901,600.0 | |
规范化 | 1 | 0.7 | 32.0 | 4.2 | 464.9 | 419.5 |
数据集 | 度量 | RedisGraph | TigerGraph | Neo4j | Neptune1 | JanusGraph | ArangoDB2 |
---|---|---|---|---|---|---|---|
graph500 | 时间 (毫秒) | 1614 | 1780 | 1,312,700.0 | N/A | N/A | N/A |
规范化 | 1 | 1.1 | 813.3 | N/A | N/A | N/A | |
时间 (毫秒) | 78730 | 63000 | N/A | N/A | N/A | N/A | |
规范化 | 1 | 0.8 | N/A | N/A | N/A | N/A |
对于并行请求测试,我们只比较了 RedisGraph 和 TigerGraph。此设置包括在同一测试机器上运行的 22 个客户端线程,总共生成了 300 个请求。下面的结果显示每个图数据库在每个深度(一步、两步、三步和六步)组合起来回答所有请求需要多长时间(以毫秒为单位)。
对于 TigerGraph,我们通过将单个请求时间的平均响应时间乘以 300 来推断结果,对于每个深度。我们认为这是最好的情况,因为 TigerGraph 已经完全使用了所有 32 个核心来处理单个请求。下次,我们将使用相同的 22 个客户端负载重复这些测试,并且我们预计(根据并行性定律以及这将为执行并行请求产生的开销)我们的结果会更好。
一步 | 两步 | 三步 | 六步 | ||||||
---|---|---|---|---|---|---|---|---|---|
数据集 | 度量 | RediGraph | Tiger | RedisGraph | Tiger | RedisGraph | Tiger | RedisGraph | Tiger |
graph500 | 时间 (毫秒) | 29 | 1,890 | 772 | 21,000 | 5,554 | 123,000 | 24,388 | 534,000 |
规范化 | 1 | 65.2 | 1 | 27.2 | 1 | 22.1 | 1 | 21.9 | |
时间 (毫秒) | 117 | 7,200 | 12,923 | 138,000 | 286,018 | 2,019,000 | 3,117,964 | 18,900,000 | |
规范化 | 1 | 61.5 | 1 | 10.7 | 1 | 7.1 | 1 | 6.1 |
我们对 v1.0 GA 版本的初步基准测试结果感到非常自豪。RedisGraph 是两年前由 Roi Lipman(我们自己的图专家)在 Redis 的黑客马拉松期间启动的。最初,该模块使用六元组存储实现,但随着时间的推移,我们看到了稀疏矩阵方法和 GraphBlas 使用的更大潜力。现在我们对这一决定有了正式的验证,RedisGraph 已发展成为一个可靠的图数据库,在负载下表现出比现有图解决方案快 6 到 60 倍的性能改进,针对大型数据集(Twitter)和快 20 到 65 倍的性能改进针对普通数据集(graph500)。
除此之外,RedisGraph 在单个请求响应时间方面优于 Neo4j、Neptune、JanusGraph 和 ArangoDB,速度提高了 36 到 15,000 倍。与使用所有 32 个核心处理单个请求的 TigerGraph 相比,RedisGraph 使用单个核心,实现了 2 倍和 0.8 倍的单个请求响应时间。同样重要的是要注意,我们没有任何查询在大型数据集上超时,也没有任何查询创建内存不足异常。
在这些测试期间,我们的工程师还分析了 RedisGraph,发现了一些可以提高性能的“低垂的果实”。除了其他内容外,我们即将发布的路线图包括:
快乐作图!
RedisGraph 团队
2019 年 1 月 17 日
在我们发布这些 RedisGraph 基准测试结果后,TigerGraph 的人员回复了一些想法。虽然我们感谢听到竞争对手的看法,但我们想回应他们对假新闻的指控。**点击这里查看我们的基准测试更新博客。**