Redis中的时序数据

对于一般的应用中,都有则记录时序性数据的需求

在物联网的项目中,这个需求更为常见,一般可能存在统计近万台设备的实时状态,包括设备ID,压力,温度,湿度,对应的时间戳

虽然Redis本职并不是存储时序性数据库的,但是如果使用Redis去存取的话,考虑使用哪些数据结构,也不枉是一个好的话题

对于此类思考,需要先了解的是,时序性数据的概念,一般时序性数据主要是插入新数据,而不会更新一个已经存在的数据,所以要求数据结构在进行插入的时候不会发生阻塞的情况

但时序性数据对读有一定的要求,简单点的是查询单个记录,再之后有对一个时间范围内的数据查询,以及对一个时间范围内的数据做聚合运算,包括计算平均值,最大 最小值

综上所述,对于时序性数据,要求数据结构支持查询的花样多,新增只需要支持尾部插入即可

Redis中提供了RedisTimeSeries这一额外模块进行支持,但是否可以使用原生的数据类型,Sorted Set或者Hash进行数据存储呢?

如果使用Sorted Set或者Hash,是否有什么缺点呢?

如果是使用Hash记录时序数据,那么存储基本如下

图片

但是查询时候会出现一些问题,就是不支持范围的查询

Hash类型的底层是哈希表,并不会做排序,所以范围查询也是需要取出key值,然后一个个的查询,效率很低

那么这时候,为了支持范围查询,Sorted Set可以上场了,支持根据元素的权重分数来排序,,而这个权重可以利用时间戳作为权重,方便进行记录

图片

使用Sorted Set保存数据之后,可以使用类似ZRANGEBYSCORE命令,根据时间戳的范围来查找一段时间内的Value了

如果想要方便的支持单值查询和范围查询,可以考虑一个数据存两个地方,分别放在Hash和Sorted Set两个地方

如果需要保证原子性,可以利用MULTI 和 EXEC命令

MULTI保证原子性的操作开始,EXEC保证原子性操作的结束

图片

这样就做到了单值和范围的查询,但是对于数据的聚合查询,Reids原生的数据类型并不支持聚合查询,为了解决这个天然的缺陷,只能考虑在客户端自行完成聚合,这有一个问题,就是会有大量的数据在Redis和客户端之间频繁传输,会导致和其他的命令竞争网络资源,系统阻塞

为了支持聚合运算,Redis提供了RedisTimeSeries来保存时序性数据

ReidsTimeSeries直接在Reids实例上进行聚合运算,减少的数据的传输,对于其的使用,需要先将其编译为动态链接库,然后进行加载

对于其支持的操作,主要有以下5个

TS.CREATE 创建时间序列数据集合

TS.ADD 命令插入数据

TS.GET 获取最新的数据

TS.MGET 根据标签获取数据集合

TS.RANGE 进行聚合计算

1.TS.CREATE

设置时间序列数据集合的key和数据的过期时间,

TS.CREATE device:temperature RETENTION 600000 LABELS device_id 1

上面命令就是

创建一个key为device:temperature,数据有效期为600s的时间序列集合,最后加上了标签属性{device_id:1},表明记录的是设备ID为1的数据

2.TS.ADD插入数据

命令如下

TS.ADD device:temperature 1596416700 25.1

插入一条数据

3.TS.GET TS.MGET

TS.GET device:temperature

获取最新的数据

TS.MGET 根据标签过滤集合

我们一开始创建队列的时候,在其中加入了集合的标签属性,那么在查询的时候就可以利用MGET,以及FILTER,过滤查询数据

TS.MGET FILTER device_id!=2

1) 1) “device:temperature:1”

2) (empty list or set)

3) 1) (integer) 1596417000

2) “25.3”

4.TS.RANGE支持需要聚合运算的范围查询

使用TS.RANGE命令指定要查询的时间范围的时候,同时用AGGREGATION参数指定要执行的聚合计算类型,包括求均值,最大最小值 求和

我们可以按照每180s的时间窗口,对其进行均值计算

TS.RANGE device:temperature 1596416700 1596417120 AGGREGATION avg 180000

和使用Hash和Sorted Set来保存时间序列数据相比,ReidsTimeSeries是专门为时间序列数据的模块

总结一下,本章说了Redis提供了时序性数据解决方案

第一种是使用原生的Hash和Sorted Set类型,将数据保存在Hash集合和Sorted Set ,但是不支持聚合运算

第二种是RedisTimeSeries模块,专门为时间序列数据设计的扩展模块,支持在Redis上进行多种数据聚合运算,避免了大量数据在实例和客户端之间进行传输,不过RedisTimeSeries的底层数据结构使用了链表,范围查询的复杂度是O(N)级别的

最后一个问题,就是使用Sorted Set作为时间序列数据,将时间戳作为Score,实际的数据作为member,这样保存数据有没有潜在的危险

首先说,对于时序性数据,一定要选择专业的时序性数据库,包含InfluxDB Opentsdb,哪怕使用ES也行,

然后上面的问题,如果使用Sorted Set作为数据结构保存时序性数据,会出现大量写入从而引起的big key问题,

而且聚合运算的受众面太小,并不适合直接作为一个内在功能

发表评论

邮箱地址不会被公开。 必填项已用*标注