使用 zrange 按周期查询 Redis 时间序列



我已经搜索并做了相当多的阅读,但找不到答案。我相信我可能在这里对缓存实现有错误的想法。

我有一组历史和当前的金融股票数据,我想保留这些数据以快速访问 API,这些数据遵循以下格式:

id: uuid
timestamp: unix_timestamp
data: {...}

目的是允许用户请求由缓存提供的数据,但是我希望用户能够提供时间范围(例如1483142400 - 1493510400(以及秒形式的时间段(例如 300、900、1800、3600、86400(。

我现在在如何处理这个问题方面陷入了两难境地,我最初的想法是将zadd的所有时间戳存储在每只股票的单个排序集中,然后使用zrange查询。但是,这将很昂贵,因为除非 Redis 能够在某个时间段内"单步执行"(如果我可以提供所有密钥,因为它们遵循非随机的一致格式(,否则我会查询太多不必要的数据。

我的第二个想法是改用单独的键,因为我的财务数据是针对股票 XYZ 的:

ZADD XYZ_300 1501200300 'data' 1501200600 'data'
ZADD XYZ_900 1501200900 'data' 1501201800 'data'
ZADD XYZ_1800 1501201800 'data' 1501203600 'data'
ZADD XYZ_3600 1501203600 'data' 1501207200 'data'

但是,这意味着我有一些冗余数据正在进行,因为所有集合都将具有 300 秒表中也可用的数据。

而且,我可能有一些股票,如XYZABCDEF。我希望能够在每小时查询上述所有股票从 3 天前到 2 天前的数据,我不确定我是否应该使用ZUNIONSTORE或某种管道来有效地执行此操作一次查询多个范围。

现在唯一的保证是我确切地知道我的密钥是什么,因为它们总是四舍五入到最接近的 00:00、05:00、15:00 和 30:00 分钟 unix 时间戳。缓存本身是从运行Django(存储json(的Python设置/查询的。可能是我最好将其存储在文件中而不是缓存中(因为我使用的是AWS,因此我可以将新的EFS存储系统用于多个服务器以共享相同的底层"硬盘/卷"(

据我了解,您有 2 个基本要求: 1. 能够在任何随机时间范围内查询 2. 按时间跨度查询结果聚合

ZRANGE基本上是一个具有(漂亮(高效查询运行时的排序集。 来自 Redis 手册:

O(log(N(+M(,其中 N 是排序集中的元素数,M 是返回的元素数。

许多人的一个常见用例是将时间序列数据保存在排序集中:

  • 每个时间戳添加一个数据键(哈希类型(,其中包含值及其标识(例如股票(。
  • 每个 ZSET 项数据必须是唯一的,因此必须将数据保存在单独的哈希键中
  • 按键查询特定股票,使用ZRANGE获取特定时间,性能相当不错。 关于这项技术的好文章可以在这里找到:https://www.infoq.com/articles/redis-time-series。

关于性能,我们需要同时查看插入和阅读:

  1. 写入性能:ZADD 是 O(log(N(( + 哈希写入性能 O(N(,其中 N 是数据键的数量(例如股票(。
  2. 读取性能:ZRANGE O(log(N(+M( + 特定键 O(1( 的 HGET 如果您有很多样本 (M(,您的读取性能将会降低。

关于要求#2: 在 redis 中进行聚合没有简单的方法。

综上所述,时间序列没有最优的数据结构,您可以使用ZSET(很多人这样做(它可以工作,但不是很优化,也不节省空间。

您可以通过以下方式进行改进:

  • 使用 LUA 代码查询原始排序集并执行一些魔术,而无需将大量数据移动到客户端。
  • 使用新的模块 API 编写自己的数据结构。

或者你可以尝试使用我编写和维护的模块:https://github.com/danni-m/redis-timeseries。 特点是:

  • 用于时间序列的高效数据存储(目前每个样本为 16 字节,im 正在处理大猩猩压缩,这将降低空间(
  • 按时间存储桶聚合查询(要求 #1(
  • 使用不同的聚合方法(最大值、最小值、平均值、总和(进行自动比较/缩减采样(一对多(
  • 用于添加和查询时间序列的非常简单的命令。

你需要有table_name、数据timestamp_in_unix

要添加

zadd table_name data timestamp_in_unix

检索所有值

zrangebyscore table_name -inf +inf 

在特定范围内检索

zrangebyscore table_name from_unix_timestamp to_unix_timestamp

我希望这有所帮助。 如果您遇到任何问题,请告诉我。

最新更新