Redis TS.ALTER 修改保留时间后旧样本何时清理
来源:17golang原创
时间:2026-10-29 15:46:39 409浏览 收藏
Redis 时序的 TS.ALTER key RETENTION 毫秒数 修改的是序列的保留策略,不是立即扫描并逐条删除旧样本的命令。需要分开看两件事:常规范围查询会按新保留窗口限制可见样本;底层旧数据块的回收由后续写入过程触发,不能把返回OK理解成内存已经按比例下降。
保留窗口以该序列的最大样本时间戳为参照,不是拿服务器当前时间倒数。停止采集以后,单纯等待一段墙钟时间,不等于序列会像设置了TTL的键一样自动推进过期窗口。
Redis 官方命令地址:https://redis.io/docs/latest/commands/ts.alter/
先区分“清理”的三种含义
假设一个设备温度序列原来保留24小时,现在只需要最近1小时。我的选择会先取决于业务目标:是让报表只读短窗口,还是希望尽快释放存储,或者必须按明确范围删除数据。这三种目标不能共用一个“清理完成”指标。
| 关心的结果 | 实际含义 | 不要据此推断 |
|---|---|---|
| 策略已修改 | 序列使用新的RETENTION值 | 旧样本已经全部物理删除 |
| 旧样本不再返回 | 查询受当前保留窗口限制 | 对应内存已全部归还 |
| 底层数据块回收 | 过期块从序列存储中移除 | 进程内存必然按同样比例下降 |
本文的取舍是基于文档与官方实现阅读提出的工程判断,不是生产事故回忆,也没有运行基准测试。时序命令要求部署本身支持该功能,不能把普通Redis键的过期机制直接套到它上面。

用最大样本时间计算窗口,不拿当前时间代替
记序列最大样本时间为T、保留时长为R。R大于0时,窗口下界通常按T减R理解;早于下界的样本属于窗口之外。这里的时间单位都是毫秒,RETENTION设置为0表示不按该策略过期。
举一个不依赖真实日期的小例子:最大样本时间为10000,R改为3000,窗口下界就是7000。样本2000在窗口外,9000在窗口内。即使你等了半小时,只要序列最大时间仍是10000,不能把边界自行改成“当前时间减3000”。
这也解释了两类常见意外。停写序列不会仅因墙钟经过就持续缩短;错误写入远未来时间戳则可能把窗口大幅推前,让正常采样落到窗口外。后者应先处理时间戳来源与数据恢复,不能靠反复改保留值掩盖。
查询不返回和底层回收,是两个层面
官方TS.ALTER说明只修改指定配置;官方RedisTimeSeries实现中,ALTER的RETENTION分支更新retentionTime,没有在这个分支直接执行全量清理。范围查询的SeriesQuery会按保留窗口限制开始时间,因此查询变短可以发生在物理回收之前。
底层SeriesTrim按块检查过期范围,而SeriesAddSample在创建新块的分支调用它。这说明“下一条样本写进去,所有窗口外字节立刻消失”也过于绝对:是否进入回收分支、块是否完全落到边界之前,都影响回收时机。这里是对官方仓库当前实现的说明,不承诺所有部署版本内部结构完全相同。
我更愿意把RETENTION当作随采集推进的生命周期策略,而不是定时释放内存的同步指令。若只依据一张范围查询结果就宣布容量回收完成,很容易把可见性与存储状态混为一谈。
按持续采集、停写归档和明确删除选择方案
| 业务负载 | 适合的处理思路 | 主要取舍 |
|---|---|---|
| 持续产生真实样本 | 修改RETENTION,由正常写入推进窗口与回收 | 接受回收不是ALTER同步完成 |
| 序列已经停写 | 明确归档和淘汰任务,不靠等待触发时序回收 | 需要额外的数据生命周期管理 |
| 需要删除确定区间 | 评估TS.DEL及其聚合约束 | 属于显式数据删除,须明确范围 |
| 整个序列都不再需要 | 按业务审批清理整个键 | 不应伪装成仅调整保留时长 |
不要为了“推动清理”随意写入一条当前时间的假温度。假样本会进入查询,可能影响聚合和下游计算,也会改变窗口参照点。持续采集系统应使用真实采样;停写系统则应明确采用归档或删除策略。

操作示例:先改策略,再分别理解配置与数据
下面命令通过shell调用redis-cli,中文注释是shell注释。请只在自己可控制的演示环境使用未占用的键名;本文未实际执行,也不提供伪造输出。
# 使用独立演示键;若TS.CREATE报键已存在,应停止,不覆盖已有业务数据。 redis-cli TS.CREATE demo:retention:temperature RETENTION 0 # 时间戳仅用于推导保留窗口,不代表真实采集时间。 redis-cli TS.ADD demo:retention:temperature 2000 18 redis-cli TS.ADD demo:retention:temperature 9000 21 redis-cli TS.ADD demo:retention:temperature 10000 22 # 修改策略为3000毫秒;这一步不等于底层存储同步清理完成。 redis-cli TS.ALTER demo:retention:temperature RETENTION 3000 # 配置与查询是两个观察面,不能用查询结果推断物理内存释放量。 redis-cli TS.INFO demo:retention:temperature redis-cli TS.RANGE demo:retention:temperature - +
按窗口推导,常规范围查询应关注7000及之后的已有样本,即9000与10000;时间2000不在新窗口内。这里没有继续添加样本,因此没有用演示制造“全部回收完成”的结论。
写应用脚本时,要在每条写命令后检查返回错误,创建失败就停止;命令列表不能不顾错误一直执行。若服务要求立即删除一个历史区间,应另做删除范围和聚合规则评估,而不是把ALTER包装成保证立即回收的按钮。
还有一个容易写错的地方:对已经存在的序列,TS.ADD里的RETENTION属于创建时选项,会被忽略。修改现有序列应该使用TS.ALTER,不能指望每次ADD都覆盖策略。
把保留时长调大,已删除的历史样本会回来吗?
不会重新生成已经被删除的数据。扩大窗口并不是恢复备份;也不应该把尚未回收的底层内容当成可靠历史存档。
把RETENTION设为0,是立即清空吗?
不是,0表示不按保留时长让样本过期,方向恰好相反。
为什么修改成功后容量没有马上明显下降?
策略生效、查询范围和存储块回收不是同一个事件,进程内存还受到分配器等因素影响。不要把ALTER成功回执解释成一个确定的容量下降比例。
依据:TS.ALTER、TS.CREATE保留规则、TS.ADD;实现细节参考官方仓库的module.c与tsdb.c。
-
374 收藏
-
398 收藏
-
117 收藏
-
426 收藏
-
171 收藏
-
422 收藏
-
491 收藏
-
226 收藏
-
409 收藏
-
418 收藏
-
243 收藏
-
256 收藏
-
225 收藏
-
378 收藏
-
292 收藏
-
325 收藏
-
397 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习