登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  Redis

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键的过期机制直接套到它上面。

保留配置、查询窗口和存储块回收的静态关系
图1:静态结构说明图。保留策略关联查询可见性和存储回收,两者是不同的观察对象,连线不表示执行先后。

用最大样本时间计算窗口,不拿当前时间代替

记序列最大样本时间为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及其聚合约束属于显式数据删除,须明确范围
整个序列都不再需要按业务审批清理整个键不应伪装成仅调整保留时长

不要为了“推动清理”随意写入一条当前时间的假温度。假样本会进入查询,可能影响聚合和下游计算,也会改变窗口参照点。持续采集系统应使用真实采样;停写系统则应明确采用归档或删除策略。

持续采集、停写序列和明确删除需求与处理方式的静态关联
图2:静态结构说明图。不同负载关联不同处理目标;这是方案关系图,不是清理流程图或实测结果。

操作示例:先改策略,再分别理解配置与数据

下面命令通过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。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>