Redis里怎么查过期数据,顺便防止它们突然没了的那些事儿
- 问答
- 2026-01-10 02:53:18
- 1
主要参考自Redis官方文档关于键过期的说明,以及《Redis设计与实现》一书中对过期键删除策略的讲解,并结合了常见的运维实践经验。)
在Redis里,数据是可以设置“保质期”的,这就像给超市里的商品贴上一个过期标签,到了时间就得下架,在Redis中,这个操作通常是通过两个命令实现的:EXPIRE key seconds(给一个键设置多少秒后过期)或者 EXPIREAT key timestamp(给一个键设置一个具体的Unix时间戳,到了那个时间点就过期)。
Redis是怎么知道哪个数据过期了呢?它内部有一个“过期字典”,你可以把它想象成一个本子,专门记录每个带过期时间的键和它具体的过期时间点,当你要读取一个键时,Redis会先翻翻这个本子,看看它是不是已经过期了。

但关键问题来了,如果一个键过期了,但一直没人来访问它,难道它就永远占着内存不走了吗?当然不是,Redis可没那么傻,它用了两种主要的策略来清理这些“赖着不走”的过期数据,这两种策略就像两个尽职尽责的清洁工,但工作方式很不一样。
第一个清洁工叫“惰性删除”。(参考《Redis设计与实现》),这个清洁工很懒,它不会主动去巡逻,只有当客户端尝试去访问一个键的时候,它才被触发工作,流程是这样的:比如你发了一个 GET mykey 的命令,Redis在返回数据之前,会先检查一下“过期字典”,看看 mykey 有没有过期,如果过期了,好,这个懒清洁工立刻出手,当场把这个 mykey 删除掉,然后告诉你这个键不存在(返回nil),这样做的好处是节省CPU资源,只在实际需要的时候才干活,非常精准,但坏处也很明显:如果一个键永远没人访问,即使它早过期了,也会一直留在内存里,成为“僵尸数据”,白白消耗宝贵的内存空间。
为了解决“惰性删除”的缺点,第二个清洁工出场了,它叫“定期删除”。(参考Redis官方文档),这个清洁工会定期(默认是每100毫秒一次)主动出来扫荡一圈,但它不是把所有的键都检查一遍,那样在数据量大的时候CPU会爆掉,它的工作方式更聪明:

- 它每次会随机抽取一定数量的键(从每个设置了过期时间的键的字典中抽样)。
- 然后检查这些被抽中的键是否过期。
- 如果过期,就删除。
- 它还会有一个限制:如果一次检查中,发现过期的键比例很高(比如超过25%),它会认为这个数据库里过期键很多,于是乎,它就不停地重复这个抽样、检查、删除的过程,直到过期的键比例降下来为止,这样可以确保能快速清理掉大量的过期键。
这两种策略是协同工作的,“惰性删除”保证了只有在访问时才做检查的成本最小化,“定期删除”则是一种主动的补偿机制,防止内存被永远不被访问的过期键占满,这是一种在CPU和内存之间取得的平衡。
说说“防止它们突然没了”的事儿,这主要涉及到数据持久化(把内存数据存到硬盘上)和主从复制(数据从一个Redis实例同步到另一个)时,过期键是如何被处理的。
首先看持久化,Redis持久化有两种方式:RDB和AOF。

- 生成RDB文件时(参考《Redis设计与实现》):当Redis执行
SAVE或BGSAVE命令来创建一个内存快照(RDB文件)时,它不会把过期的键保存进去,因为RDB代表的是某个时间点的数据全量快照,过期的数据自然没资格入选,当你用一个包含过期键的RDB文件恢复数据库时,这些键在恢复的那一刻就已经是过期的状态了,之后会被上述的清洁工正常清理掉。 - 使用AOF日志时(参考Redis官方文档):AOF是记录每一个写命令的日志,当一个键因为过期被删除时(无论是惰性删除还是定期删除),Redis会追加上一条
DEL key命令到AOF文件里,这样,当重启后重新播放AOF日志来恢复数据时,播放到这条DEL命令,就会把这个键删除,从而保证了数据的一致性。
然后是主从复制的情况,这里有个需要特别注意的“坑”。(这是分布式系统中的常见问题,在Redis的复制机制中尤为明显),在Redis的主从架构中,只有主节点有权决定一个键是否过期(即由主节点执行惰性删除和定期删除),主节点在删除一个过期键后,会向所有从节点发送一条DEL命令,从节点收到后才会删除自己本地的这个键。
这就导致了一个现象:在从节点上,即使一个键已经过期了,只要主节点还没删除它(比如主节点还没来得及定期抽样抽到它,或者一直没人访问它),这个键在从节点上依然是存在的,如果你直接去读从节点,可能会读到本应过期的数据!这也就是所谓的“突然没了”的另一种反面——“突然还在”。
为了避免这个问题,重要的建议是:在读写分离的场景下,应用程序应该始终从主节点读取可能会过期的数据,因为只有主节点能保证返回的是经过过期检查的最新状态,如果非要从从节点读,那就要在业务逻辑层面做好兼容,意识到可能会读到过期数据的风险。
为了防止大量数据同时过期导致的“缓存雪崩”(即大量数据在同一时刻失效,导致所有请求都砸向数据库),在设置过期时间时,最好加上一个随机扰动值,原本都设置1小时后过期,可以改成在1小时的基础上,加上一个0到5分钟的随机数,让过期时间分散开,避免集中删除对系统造成压力。
Redis通过“惰性删除”和“定期删除”两种策略来清理过期数据,并在持久化和主从复制过程中有相应的机制来保证最终一致性,但作为使用者,我们需要理解这些机制背后的原理和潜在陷阱(尤其是主从复制下的过期读取问题),并采取相应的措施(如从主读、分散过期时间)来确保业务的稳定运行。
本文由邝冷亦于2026-01-10发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/77808.html
