Redis 过期键区分主动过期与访问时删除的实现方法
线上运维缓存的时候经常碰到这类怪事:监控里看键的剩余存活时间还没到0,下次请求过来读这个键直接返回nil,甚至有时候跨节点统计过期键的数量对不上,排查半天找不到手动删键的痕迹。这类现象本质上就是Redis对过期键用了两套独立的删除逻辑,区分后台主动过期清理、和用户访问键时才触发的被动删除,两种机制并行跑才会出现我们感知上的"数据不一致"。
缓存排查里最容易误判的一幕是:刚给 Redis 键设置了过期时间,过一会儿再看却发现键不见了;另一个低频键则像“过期了还占着位置”。这通常不是 EXPIRE 失效,而是 Redis 同时采用了访问时处理和后台主动清理两条路径。
官方文档地址:https://redis.io/docs/latest/commands/expire/
判断过期键先看 TTL:正数表示仍有剩余时间,-1表示键存在但没有过期时间,-2表示键不存在。不要把“TTL 到零的瞬间”和“后台删除完成的瞬间”当成同一件事。
- 客户端访问到已经到期的键时,Redis 会在访问路径上处理它。
- 没有再次访问的过期键,由后台周期性抽样清理,删除时刻不是业务定时器回调。
TTL适合秒级判断,PTTL适合毫秒级排查;-1与-2的含义完全不同。
先固定 TTL 的三种返回值
排查时不要先用业务复杂的 key。先建立三个最小状态:一个带 10 秒过期时间的键、一个永久键、一个不存在的键。下面的命令是示例检查顺序,注释说明每条命令想确认什么。
# 创建一个短期键,便于观察剩余时间 redis-cli SET demo:expire "v" # 设置 10 秒超时;返回 1 代表设置成功 redis-cli EXPIRE demo:expire 10 # 返回剩余秒数,通常是 9 到 10 之间 redis-cli TTL demo:expire # 创建一个没有过期时间的永久键 redis-cli SET demo:persistent "v" # -1 表示键存在,但没有关联 expire redis-cli TTL demo:persistent # 检查不存在的键;-2 与 -1 不要混淆 redis-cli TTL demo:missing
表格可以把结果直接固定下来:
| TTL 结果 | 键状态 | 排查含义 |
|---|---|---|
| 大于等于 0 | 存在过期时间 | 仍在倒计时,数值会随时间减少 |
| -1 | 键存在但无过期时间 | 检查是否被 SET、RENAME 或 PERSIST 改成持久键 |
| -2 | 键不存在 | 可能已过期、被 DEL,或根本没有创建成功 |

主动过期与访问时删除的分工
Redis 官方把过期处理分成两种方式。第一种是访问时处理:客户端执行读取或其他会触碰该 key 的命令,Redis 发现它已经超时,就把它视作过期并完成删除。第二种是主动过期:后台周期性从带过期时间的键中抽样,把已经到期的键清掉。
两条路径解决的是不同问题。访问时处理保证“读到过期值”这件事不会继续发生;主动清理则负责处理那些再也不会被访问的冷键。如果只依赖访问,冷键会长期占用过期索引和内存;如果只依赖后台逐个扫描,又会带来不必要的扫描成本。因此,低频键在过期后短暂留存于内部结构,并不等于业务读取会拿到旧值。

按低干扰顺序排查业务缓存
真实故障里最重要的是先记录状态,再做读取。读取本身可能触发访问时处理,所以不要只凭一次 GET 后看到的 nil 推断后台已经扫过该键。
# 先检查剩余时间,保留原始判断依据 redis-cli TTL cache:user:42 # 用 PTTL 补充毫秒级剩余时间,适合临界点排查 redis-cli PTTL cache:user:42 # 再判断 key 是否仍存在;-1、-2 的语义仍以 TTL 为准 redis-cli EXISTS cache:user:42 # 最后读取值;到期键可能在这一步被访问时处理 redis-cli GET cache:user:42
如果第一次 TTL 返回正数,紧接着 GET 返回空,先考虑两个可能:键在两条命令之间自然到期,或者客户端访问的是不同数据库、不同节点。若 TTL 返回 -1,不要继续等待过期,而要追查写入逻辑是否用不带 EX 选项的 SET 覆盖了原键;官方文档也说明,覆盖内容的命令可以清除原有超时。
时间精度和边界要单独记录
TTL 返回秒,适合业务级观察;PTTL 返回毫秒,适合判断是否正在跨过过期临界点。Redis 的过期信息以绝对时间保存,实例重启或加载持久化数据时,机器时钟仍然会影响“现在是否已到期”的判断,因此排查跨机器问题时要同时记录节点和系统时间。
复制场景也不要把副本上的观察等同于主节点的过期动作。常规复制中,过期由主节点处理并传播删除效果,副本等待主节点的删除操作。缓存业务只需要记住一个实用边界:过期策略决定“何时不再向客户端提供该键”,不承诺每个键都在同一毫秒从所有内部结构中消失。
最终检查清单可以压缩为:先 TTL,再用 PTTL 观察临界点;确认数据库和节点;检查写入命令是否覆盖或 PERSIST;最后才用 GET 验证业务值。
相关问题
TTL 返回 -1 是不是马上就会过期
不是。-1 表示键存在但没有过期时间,通常需要检查写入、覆盖或 PERSIST 逻辑。
TTL 返回 -2 能证明键是被过期删除的吗
不能。-2 只表示当前键不存在,也可能是 DEL、覆盖其他数据库或创建失败造成的。
过期时间到了,为什么内存监控不会同步下降
键会先在访问路径或主动抽样中被处理,内存分配器和监控采样又有自己的回收与刷新节奏,二者不是同一时刻。
什么时候应该使用 PTTL
当问题发生在秒级临界点、需要判断两个命令之间是否已经跨过到期时刻时,使用 PTTL;普通缓存巡检使用 TTL 即可。
Go encoding/xml用 Token 读取混合内容的解析方法
- 上一篇
- Go encoding/xml用 Token 读取混合内容的解析方法
- 下一篇
- Go os/exec为命令设置最小环境变量的配置方法
-
- 数据库 · Redis | 21分钟前 | Redis · redis maxmemory maxmemory-policy evicted_keys INFO stats
- Redis 内存淘汰变更策略后观察淘汰计数的实现方法
- 223浏览 收藏
-
- 数据库 · Redis | 3小时前 | 数据安全 · 性能排查 · appendfsync AOF重写 BGREWRITEAOF Redis AOF Redis持久化 Redis延迟排查
- Redis AOF理解重写期间的磁盘与延迟的实现方法
- 218浏览 收藏
-
- 数据库 · Redis | 4天前 |
- Redis Cluster key slot用 CRC16 解释跨槽排查的实现方法
- 436浏览 收藏
-
- 数据库 · Redis | 4天前 | Redis · 脚本 · lua · eval Redis Lua redis.call redis.pcall
- Redis Lua 脚本返回结构化状态码避免业务歧义的实现方法
- 493浏览 收藏
-
- 数据库 · Redis | 4天前 | redis zset 游标分页 Sorted Set ZRANGEBYSCORE Redis分页
- Redis ZSET 分页用游标实现稳定范围分页的实现方法
- 440浏览 收藏
-
- 数据库 · Redis | 4天前 | Redis · BCAST 客户端缓存 Prefix Redis CLIENT TRACKING
- Redis CLIENT TRACKING用 BCAST 接收客户端缓存失效通知的实现方法
- 361浏览 收藏
-
- 数据库 · Redis | 4天前 |
- Redis 客户端连接池 timeout 与命令执行超时如何区分
- 340浏览 收藏
-
- 数据库 · Redis | 4天前 | Redis · 故障排查 · 内存优化 · redis 内存排查 INFO memory MEMORY DOCTOR MEMORY STATS
- Redis MEMORY DOCTOR 输出如何转成排查顺序
- 277浏览 收藏
-
- 数据库 · Redis | 4天前 |
- Redis RESP3 Push 类型通知客户端如何兼容
- 415浏览 收藏
-
- 数据库 · Redis | 4天前 |
- Redis ACL 的 key pattern 为什么放行了意外键
- 215浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 121次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 196次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 139次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 114次使用
-
- CMMLU
- 深入了解CMMLU中文评估基准,涵盖67个学科主题,提供数据集下载、Zero-shot/Five-shot评估方法及排行榜,助力优化中文语言模型性能。
- 96次使用
-
- Go与Redis实现分布式互斥锁和红锁
- 2022-12-22 117浏览
-
- Go+Redis实现延迟队列实操
- 2023-02-23 426浏览
-
- 一文搞懂Go语言操作Redis的方法
- 2023-01-07 171浏览
-
- Golang分布式应用之Redis示例详解
- 2023-01-07 113浏览
-
- Go Redis客户端使用的两种对比
- 2022-12-30 195浏览

