RedisTimeSeries是Redis的一个时序数据模块,专门用来处理带时间戳的指标数据。它的降采样聚合能力解决的是一个很实际的问题:原始采样点太密、太多,直接全量保留内存吃不消,但把数据直接丢掉又会让历史趋势无从查询。降采样的思路是按固定时间窗口把细粒度数据压缩成聚合值,比如每秒一条的数据压缩成每分钟一条的平均值,数据量缩小六十倍,趋势信息却基本保留。这篇文章详细讲讲RedisTimeSeries里降采样聚合的配置方法、窗口对齐规则和实际使用中的注意事项。

降采样的基本原理与核心命令
RedisTimeSeries的降采样依赖两条序列的配合:一条是原始序列,负责接收高频写入;另一条是目标序列,负责保存聚合后的结果。两者通过一条聚合规则绑定在一起。当数据写入原始序列时,模块会根据聚合规则自动把落入同一个时间窗口内的数据点压缩成单条聚合记录写入目标序列,整个过程对客户端透明,不需要业务代码做任何额外处理。
创建规则的命令是TS.CREATERULE,它的基本语法是TS.CREATERULE source_key dest_key AGGREGATION aggregator bucketDuration。其中source_key是原始序列,dest_key是目标序列,aggregator是聚合函数,bucketDuration是窗口时长。目前支持的聚合函数包括sum、min、max、avg、range、count、first、last、std.p、std.s、var.p、var.s、twa等十多种,覆盖了常见的统计需求。
实际操作通常分两步,先创建序列再建立规则:
127.0.0.1:6379> TS.CREATE sensor:temp:raw RETENTION 86400000 DUPLICATE_POLICY LAST OK 127.0.0.1:6379> TS.CREATE sensor:temp:1m RETENTION 2592000000 OK 127.0.0.1:6379> TS.CREATERULE sensor:temp:raw sensor:temp:1m AGGREGATION avg 60000 OK
上面这段命令做的事情是:创建一条原始温度序列,只保留一天的原始数据;再创建一条目标序列保留三十天;最后建立规则,把原始数据按六十秒窗口取平均值压缩到目标序列。写入sensor:temp:raw的数据会自动同步到sensor:temp:1m,原始数据过期后,分钟级的聚合数据依然可以查询。
bucketDuration的时间窗口划分与对齐规则
很多初学者容易忽略的一点是,降采样的时间窗口并不是从第一条数据到达的时间开始算的,而是按Unix时间戳对齐到固定的边界。比如设置60000毫秒(一分钟)的窗口,所有窗口的起点都是整分钟,比如10:00:00到10:00:59是一个桶,10:01:00到10:01:59是下一个桶。这种对齐方式保证了不同序列、不同时间段的数据窗口边界一致,方便做对比和关联查询。
窗口的聚合结果只有在窗口关闭后才会写入目标序列。也就是说,10:00这一分钟内的数据,要等到10:01:00之后第一条数据写入或者被处理时,才会真正生成10:00这个桶的聚合值并落到目标序列上。如果你发现最新一分钟的聚合数据查询不到,多半就是这个原因,这不是bug,而是窗口尚未关闭的正常表现。
bucketDuration支持毫秒精度的任意数值,但实际使用中建议配合时间单位使用可读性更好的写法,比如1m表示一分钟,1h表示一小时,1d表示一天。多个规则可以叠加,例如原始数据按1m降采样,1m序列再按1h降采样,形成多级压缩链路:
127.0.0.1:6379> TS.CREATERULE sensor:temp:1m sensor:temp:1h AGGREGATION avg 3600000 OK 127.0.0.1:6379> TS.RANGE sensor:temp:1h - + LIMIT 10 1) 1) (integer) 1717000000000 2) 25.4
这种链式降采样的好处是可以按查询粒度灵活选择序列,看最近一小时用原始数据,看最近一周用分钟序列,看最近一年用小时序列,每次查询的数据量都被控制在一个合理的范围内。
DuplicatePolicy与聚合函数的选择策略
在配置原始序列时,DUPLICATE_POLICY参数值得特别关注。当同一个时间戳有多个数据点写入时,这个策略决定了如何处理冲突,可选值包括LAST、FIRST、MIN、MAX、SUM、AVG等。默认策略是BLOCK,也就是直接报错拒绝写入。对降采样场景来说,一般建议用LAST覆盖旧值,因为传感器类数据通常以最新读数为准。
聚合函数的选择需要结合指标本身的含义。counter类指标比如请求总数、字节数,适合用sum,因为窗口内的增量求和才有业务意义;gauge类指标比如CPU使用率、温度,适合用avg或者twa,twa是时间加权平均,考虑了每个采样点的持续时长,比简单平均更精确;对于延迟、响应时间这类需要关注极端值的指标,min和max更合适;range(最大值减最小值)则常用来观察波动幅度。
需要注意一个细节:avg、std.s这些聚合函数依赖窗口内的多个数据点,如果某个窗口只有一条数据,avg的结果就等于这条数据本身,std.s则无法计算会返回空。因此在采样频率不稳定、可能长时间没有数据的场景下,降采样结果可能出现空窗,业务侧查询时要做好判空处理。
保留策略搭配与常见踩坑点
降采样通常要和RETENTION(数据保留时长)配合使用才能发挥价值。典型的配置是:原始序列保留一天或几天,分钟级序列保留一个月,小时级序列保留一年。这样内存占用被限制在一个可预估的范围内,同时不同时间跨度的查询都有合适粒度的数据可用。RETENTION的单位是毫秒,创建时指定,也可以用TS.ALTER在后期调整。
有几个容易踩的坑需要提醒。第一,目标序列的RETENTION一定要大于等于窗口时长,否则聚合结果可能还没写入就已经过期了。第二,删除规则用TS.DELETERULE,删除规则不会删除目标序列里已经生成的数据,需要手动清理。第三,规则只在数据写入时触发,如果先建了规则再补写历史数据,历史数据同样会被聚合,这一点在数据回补时要心里有数。第四,一个源序列最多可以绑定任意多条规则,但一个目标序列只能被一条规则写入,试图给同一个目标序列再建规则会报错。
127.0.0.1:6379> TS.DELETERULE sensor:temp:raw sensor:temp:1m OK 127.0.0.1:6379> DEL sensor:temp:1m (integer) 1
最后补充一点,如果用的是Redis Enterprise或者Redis Stack,降采样规则还可以通过TS.INFO查看绑定关系,返回结果中的rules字段会列出该序列作为源的所有目标序列和聚合配置,排查问题时非常方便。整体来看,RedisTimeSeries的降采样聚合配置并不复杂,关键在于想清楚每个粒度序列的聚合函数和保留时长,让存储成本和查询体验达到平衡。
RedisTimeSeries降采样时序数据聚合修改时间:2026-09-09 23:34:44