RedisTimeSeries是Redis官方生态中一个专门处理时间序列数据的模块。它解决的问题非常具体:当你需要存储大量带时间戳的数据点,并且要按时间范围查询、做聚合统计时,原生的Redis数据结构都不太好用。用String存每个数据点,键数量会爆炸;用List或ZSet存,虽然能按范围取数据,但聚合计算、降采样这些高频需求都得自己写逻辑。RedisTimeSeries把这些能力直接内置了,一条命令就能完成创建、写入、按时间范围聚合查询,在物联网监控、系统指标采集、金融行情等场景中表现出色。

RedisTimeSeries的基本概念和核心命令
RedisTimeSeries中的每条时间序列都是一个独立的键,类型为TSDB-TYPE。每个序列可以设置保留时间(RETENTION)、标签(LABELS)和降采样规则(COMPACTION),数据点由时间戳和浮点值组成。最基础的写入命令是TS.ADD,查询用TS.RANGE,这两个命令覆盖了绝大多数使用场景。
先看一个创建和写入的例子:
# 创建一个带标签的时序键,保留7天的数据 TS.CREATE sensor:temp:1 RETENTION 604800 LABELS device_id 1 location beijing # 写入数据点:时间戳 数值 TS.ADD sensor:temp:1 1700000000000 25.6 TS.ADD sensor:temp:1 1700000060000 25.8 # 使用自动时间戳写入(服务器当前时间) TS.ADD sensor:temp:1 * 26.1
RETENTION参数的单位是毫秒,设置为604800表示数据保留7天,超过保留期的旧数据会被自动清理,不需要手动删除。这个设计对监控类场景非常友好,避免了内存无限增长的问题。LABELS则是一组键值对,是后面实现多序列过滤查询的基础。
查询数据使用TS.RANGE命令:
# 查询某个时间范围内的原始数据 TS.RANGE sensor:temp:1 1700000000000 1700003600000 # 按每10分钟聚合,取平均值,配合标签过滤 TS.RANGE sensor:temp:1 1700000000000 1700003600000 AGGREGATION avg 600000
如果不确定精确的时间戳,可以用TS.GET获取最新值,或者用TS.INFO查看序列的元信息,包括数据点总数、第一条和最后一条的时间戳、内存占用等,这些信息在做容量评估时很有用。
标签过滤与多序列查询
单条序列的查询只是基础,真实业务中往往需要跨序列检索。比如一个机房有上千个温度传感器,你想找出北京地区所有设备的最新温度,逐个查询显然不现实。RedisTimeSeries的标签索引就是为了解决这个问题。
通过TS.MRANGE命令可以按标签过滤批量查询:
# 查询所有location为beijing的传感器最近一小时数据,按5分钟聚合 TS.MRANGE - + AGGREGATION avg 300000 FILTER location=beijing # 组合过滤:device_id为1或2,且location不为shanghai TS.MRANGE - + FILTER device_id=(1,2) location!=shanghai # 使用WITHLABELS返回标签信息 TS.MRANGE - + WITHLABELS FILTER location=beijing
FILTER语法支持等值匹配、多值匹配(用圆括号和逗号)、不等于,但不支持前缀模糊匹配,所以标签设计要提前规划好。一个实用建议是:把高频过滤的维度都设计成标签,比如设备ID、机房、业务线,而不要把这些信息编码到键名里。键名编码虽然也能定位,但无法享受索引带来的批量查询能力。
还有一点需要注意,标签在创建序列时设置后并不是完全不可变的,可以用TS.ALTER修改标签,但频繁修改标签会影响索引性能,应该尽量避免。
降采样规则与数据压缩策略
时序数据有个典型矛盾:原始数据精度高但体量大,历史数据只需要粗粒度。比如实时告警需要秒级数据,但看一个月的趋势图,小时级聚合就足够了。RedisTimeSeries通过COMPACTION规则实现自动降采样。
# 创建原始序列,保留1天 TS.CREATE sensor:temp:1 RETENTION 86400 LABELS device_id 1 # 创建降采样目标序列,保留30天,每小时一个点 TS.CREATE sensor:temp:1:1h RETENTION 2592000 LABELS device_id 1 # 建立降采样规则:每1小时取平均值写入目标序列 TS.CREATERULE sensor:temp:1 sensor:temp:1:1h AGGREGATION avg 3600000
配置之后,每次向原始序列写入数据,模块会自动检查是否需要生成聚合点,完全不需要应用层做任何额外处理。常用的聚合方式包括avg、sum、min、max、count、first、last、range等,可以按需组合出多个不同粒度的目标序列,比如1分钟、1小时、1天各一套,形成多层数据结构。
这种多级降采样的内存收益非常可观。假设每秒一个数据点,一千个传感器一年不清理就是三百多亿个点,而按1小时降采样后只剩不到九百万个点,内存压力直接下降几个数量级。另外,RedisTimeSeries默认使用Gorilla压缩编码,相邻时间戳和数值变化小时存储开销很小,相同数据量下比ZSet方案节省大量内存。
与原生Redis方案的对比及适用场景
在没有RedisTimeSeries之前,常见的做法是用ZSet存时序数据,member放值和序列ID,score放时间戳。这个方案能用,但有几个明显短板:按时间范围取数据需要ZRANGEBYSCORE,做聚合必须把数据拉回客户端计算,网络开销大;没有自动过期清理,需要定期删除旧数据;没有标签索引,多序列管理全靠键名约定。
RedisTimeSeries则把这些都内置了,服务端直接完成聚合计算,减少网络传输;RETENTION自动清理过期数据;标签索引支持灵活的多维查询。下表是两种方案的直观对比:
| 能力 | ZSet方案 | RedisTimeSeries |
|---|---|---|
| 范围查询 | ZRANGEBYSCORE | TS.RANGE原生支持 |
| 服务端聚合 | 不支持 | 支持avg/sum/min/max等 |
| 自动过期 | 需手动清理 | RETENTION自动清理 |
| 多序列过滤 | 键名约定 | 标签索引 |
| 降采样 | 应用层实现 | COMPACTION自动完成 |
当然它也不是万能的。如果你的场景只需要保存少量状态值,或者需要按值反查时间戳,那普通的Hash或ZSet更简单直接。RedisTimeSeries最适合的是高频写入、按时间范围读取、需要聚合统计的场景,典型应用包括服务器CPU和内存监控、物联网设备数据采集、应用性能指标APM存储等。
部署方面,RedisTimeSeries以模块形式加载,Redis Cloud和Redis Stack中已内置,自建环境可以通过redis.io下载源码编译,或者使用Docker镜像redis/redis-stack直接启动,然后用MODULE LOAD命令加载即可,客户端方面Java的Jedis、Python的redis-py都对相关命令有封装,接入成本不高。
RedisTimeSeries时序数据Redis扩展模块修改时间:2026-09-14 02:54:43