简单地说,我们现在是Redis
今天我们很高兴地宣布,通用可用性(GA)再贴现时间序列v1.0。RedisTimeSeries是Redis开发的Redis模块,以提高您的经验管理时间序列数据与Redis。我们在6个月前发布了RedisTimeSeries的预览/测试模式,感谢社区和我们的客户在我们共同开发第一个GA版本时提供的所有反馈和建议。为了标记这个版本,我们执行了一个基准测试,与Redis中的其他时间序列方法相比,RedisTimeSeries实现了每秒125K次查询。浏览完整的结果,或者先花点时间了解一下是什么让我们构建了这个新模块。
许多Redis用户使用Redis的时间序列数据已经有近十年的时间了,他们很高兴并且很成功。我们稍后会解释,这些开发人员使用的是Redis的通用原生数据结构ag万博下载万博最新版本下载苹果。因此,让我们先退一步来解释为什么我们决定构建一个具有专用时间序列数据结构的模块。
在DB-engines下面的趋势图,你可以看到时间序列数据库最近变得最流行。除了不断增长的数据量和新的时间序列用例,自动驾驶汽车、算法交易、智能家居、在线零售等,我们认为这一趋势有两个主要的技术原因。
第一个原因是时间序列数据的查询模式和规模与构建现有数据库技术的目的不同。虽然大多数数据库的设计目的是提供更多的读而不是写,但时间序列用例对大量数据的吸收率很高,读查询的数量较低。在根本原因分析用例中,读取是零星的,并且只涉及数据集的随机部分。在训练AI模型的用例中(例如,用于传感器数据中的异常检测),通常读将跨越更大的数据集,但发生的频率仍然明显低于写。因为复述的可伸缩的架构,它提供了低延迟的高写吞吐量,Redis自然适合当前的时间序列查询模式。
这种趋势的第二个原因是,在传统的数据库技术中,不存在处理时间序列所需的工具集。有效利用资源需要几项结构性变化,例如历史时间序列数据的自动下采样和双脉冲编码,以及直观查询和聚合时间序列数据的功能。传统的数据库技术在应用程序端引入了大量的工作,以解决保留、向下采样和聚合等特性。
在Redis,我们坚信自己吃狗粮。对于我们的云产品(它管理运行在数千个Redis企业集群上的100多万个Redis数据库),我们从内部Redis数据库中的每个集群收集指标。在一个增强我们自己的基础设施指标的内部项目中,我们亲身体验了将核心Redis数据结构用于时间序列用例的局限性和开发工作。我们认为一定有更好万博体育彩更有效的方法。除了上述特定于工具集的功能外,我们还需要现成的辅助索引,以便能够高效地查询时间序列集。
在Redis中有两种使用时间序列的方法,同时重用现有的数据结构:排序集和流。许多文章解释了如何用Redis核心数据结构建模时间序列。下面是我们将在稍后的基准测试中使用的一些关键原则。
A排序集存储值通过他们的分数.在时间序列数据的情况下,分数是观察事件的时间戳。的价值重复时间戳,后跟一个分隔符和实际测量值,例如"
这种方法的缺点是:
Redis Streams是最近添加的数据结构(因此目前较少用于时间序列),它消耗的内存比排序集更少,并使用递交(基数树的单独实现)。一般来说,与排序集相比,Redis Streams增强了插入和读取的性能,但仍然遗漏了特定于时间序列的工具集,因为它被设计为通用数据结构。
这种方法的缺点是:
在RedisTimeSeries中,我们引入了一种新的数据类型,它使用固定大小的内存块作为时间序列样本,并通过与Redis Streams相同的基数树实现进行索引。使用Streams,您可以创建限制流,有效地限制了邮件的数量。在RedisTimeSeries中,可以应用以毫秒为单位的保留策略。这对于时间序列用例更好,因为它们通常对给定时间窗口中的数据感兴趣,而不是固定数量的样本。
如果你想无限期地保留所有的原始数据点,你的数据集将会随着时间线性增长。然而,如果您的用例允许您拥有更少的细粒度数据,那么可以应用向下采样。这允许您使用给定的聚合函数为给定的时间窗口聚合原始数据,从而保留更少的历史数据点。RedisTimeSeries支持将采样使用以下聚合:平均,总和,最小,最大,范围,计数,第一和最后。
当使用Redis的核心数据结构时,你只能通过知道持有时间序列的确切密钥来检索时间序列。不幸的是,对于许多时间序列用例(例如根本原因分析或监视),应用程序并不知道它要查找的确切密钥。这些用例通常希望查询一组在几个维度中相互关联的时间序列,以提取您需要的洞察力。你可以用核心的Redis数据结构来创建你自己的二级索引,但这将带来很高的开发成本,并要求你管理边缘情况,以确保索引是正确的。
RedisTimeSeries基于“字段值”对(也就是标签)为您进行索引,您可以将其添加到每个时间序列,并用于在查询时进行过滤(这些过滤器的完整列表可在我们的文档).下面是一个使用两个标签(sensor_id和area_id分别是值为2和32的字段)和60000毫秒保留窗口创建时间序列的示例:
TS.CREATE temperature RETENTION 60000 LABELS sensor_id 2 are_id 32
当您需要查询时间序列时,如果您只对给定时间间隔内的平均值感兴趣,那么将所有原始数据点流化是很麻烦的。RedisTimeSeries遵循Redis的哲学,只传输所需的最小数据,以确保最低的延迟。下面是一个跨越5,000毫秒时间桶的聚合查询示例聚合函数:
127.0.0.1:6379> ts .范围温度:3:32 1548149180000 1548149210000聚集平均5000
1) 1)(整数)1548149180000
2)“26.199999999999999”
2) 1)(整数)1548149185000
2)“27.399999999999999”
3) 1)(整数)1548149190000
2)“24.800000000000001”
4) 1)(整数)1548149195000
2)“23.199999999999999”
5) 1)(整数)1548149200000
2)“25.199999999999999”
6) 1)(整数)1548149205000
2)“28”
7) 1)(整数)1548149210000
2)“20”
RedisTimeSeries与现有的时间序列工具进行了几个集成。其中之一就是我们的一体化RedisTimeSeries适配器对于普罗米修斯,它将所有监控指标都保存在RedisTimeSeries中,同时利用整个普罗米修斯生态系统.
此外,我们还为格拉凡纳和电报.这个存储库包含RedisTimeSeries的docker compose设置、其远程写入适配器Prometheus和格拉凡纳. 它还配有一套数据生成器和预先构建的Grafana仪表盘。
为了演示我们新开发的GA RedisTimeSeries模块的全部功能,我们用三种处理时间序列数据的常用技术对其进行了基准测试。为了比较Sorted set、Streams和RedisTimeSeries在输入、查询时间和内存消耗方面的性能,我们使用了客户机-服务器设置和两台独立的机器。
具体而言,我们的设置包括:
Redis Streams允许你为给定的时间戳在消息中添加几个字段值对。对于每个设备,我们收集了10个指标,这些指标被建模为一个流消息中的10个独立字段。
对于排序集,我们以两种不同的方式对数据进行建模。对于“每个设备的排序集”,我们连接度量并用冒号分隔,例如“
当然,这会消耗更少的内存,但需要更多的CPU周期才能在读取时获得正确的指标。这也意味着改变每个设备的参数数量并不是一件简单的事情,这就是为什么我们也测试了第二种Sorted Set方法。在“每个度量的排序集”中,我们将每个度量保持在自己的排序集中,并且每个设备有10个排序集。我们以“
另一种替代方法是通过创建一个具有唯一键的散列来跟踪给定设备的给定时间戳的所有测量值,从而规范化数据。这个键将是已排序集合中的值。然而,必须访问许多哈希来读取时间序列将在读取时间的巨大成本,所以我们放弃了这条路径。
在RedisTimeSeries中,每个时间序列都包含一个指标。我们选择这个设计是为了维护Redis原则,即小键数量多好过大键数量少。
需要注意的是,我们的基准并没有利用RedisTimeSeries现成的辅助索引功能。该模块在每个分片中保留一个部分二级索引,并且由于该索引继承了它所索引的键的相同哈希槽,因此它始终托管在同一分片上。这种方法将使本机数据结构的设置更加复杂,难以建模,因此为了简单起见,我们决定不将其包括在基准测试中。此外,虽然Redis Enterprise可以使用万博体育彩代理将命令的请求展开,例如TS.MGET和梅兰奇对于所有碎片和聚合结果,我们也选择不在基准测试中利用这一优势。
对于基准测试的数据摄入部分,我们通过测量每秒可以摄入多少设备的数据来比较这四种方法。我们的客户端有8个工作线程,每个线程有50个连接,每个请求有50个命令。
复述,流 | 再贴现时间序列 | 排序设置 每一个设备 |
排序设置 每一个指标 |
|
命令 | XADD | 麦德 | ZADD | ZADD |
管道 | 50 | 50 | 50 | 50 |
每个请求的度量 | 5000 | 5000 | 5000 | 500 |
#键 | 4000 | 40000 | 4000 | 40000 |
表1:每种方法的摄取细节
我们所有的摄取操作都是在亚毫秒延迟下执行的,尽管两者都使用相同的Rax数据结构,但RedisteSeries方法的吞吐量略高于Redis流。
可以看到,使用排序集的两种方法产生的吞吐量非常不同。这显示了始终针对特定用例构建方法原型的价值。正如我们将在查询性能上看到的,每个设备的Sorted Set提高了写吞吐量,但以查询性能为代价。对于您的用例来说,这是在输入、查询性能和灵活性(记住我们前面提到的数据建模注释)之间的权衡。
我们在这个基准测试中使用的读查询查询了单个时间序列,并通过保持每个时间段中观察到的最大CPU百分比,将其聚合到一个小时时间段中。我们在查询中考虑的时间范围正好是一个小时,因此返回了一个最大值。对于RedisTimeSeries,这是开箱即用的功能(如前所述)。
TS.RANGE cpu_usage_user{1340993056} 1451606390000 1451609990000聚合最大3600000
对于Redis Streams和Sorted Sets方法,我们创建了下面的LUA脚本. 客户端再次拥有8个线程和50个连接。因为我们执行了相同的查询,所以只命中了一个碎片,在所有四种情况下,这个碎片在100%的CPU下最大化。
在这里,您可以看到为给定的用例提供专用的数据结构以及与之一起运行的工具箱的真正威力。RedisTimeSeries完全超越了其他所有方法,并且是唯一实现毫秒级响应时间的方法。
在Redis Streams和Sorted Set方法中,样本都是作为字符串保存的,而在RedisTimeSeries中则是一个double。在这个特定的数据集中,我们选择了一个0-100之间的整数的CPU度量值,因此它作为一个字符串消耗了两个字节的内存。然而,在RedisTimeSeries中,每个指标都有64位精度。
与这两种排序Set方法相比,RedisTimeSeries可以显著减少内存消耗。考虑到时间序列数据的无界特性,这通常是评估需要保留在内存中的总体数据集大小的关键标准。Redis Streams进一步减少内存消耗,但当需要更高精度的更多数字时,它将等于或高于RedisTimeSeries。
在选择方法时,您需要了解时间序列用例的摄取率、查询工作负载、总体数据集大小和内存占用。正如我们所见,在Redis中有几种建模时间序列数据的方法,每种方法都有不同的特征。RedisTimeSeries提供了一种将时间视为头等公民的新方法,并提供了前面描述的开箱即用的时间序列工具包。它结合了高效的内存使用和非凡的查询性能,并且在输入期间开销很小。这将实时分析时间序列数据的愿望变成了现实。
我们对RedisTimeSeries的1.0 GA版本所取得的成绩感到满意,但这只是开始。我们很乐意听取您的反馈,以便将其纳入我们的路线图中。同时,以下是我们下一步计划的事项:
我们坚信,所有具有时间序列用例的Redis用户都将从使用RedisTimeSeries中受益。如果你仍然不相信,想自己尝试一下,这里有一个快速入门指南.