Redis集群里怎么快速找到那些快过期的键,实用又省事的方法分享
- 问答
- 2025-12-28 01:50:46
- 1
在网上查资料的时候,看到一位网名叫“Redis实战家”的朋友在他的博客里分享过一个很实在的观点,他说,在Redis集群里想精确地、一个不漏地找出所有快过期的键,其实并没有那种像在单机Redis里执行SCAN命令然后判断TTL那么简单直接的“银弹”,主要是因为数据分散在不同的节点上,而且集群设计初衷是为了高性能和扩展性,而不是这种全局性的扫描操作,这并不意味着我们没办法,只是需要一些更巧妙和省资源的思路。
有什么实用又省事的方法呢?根据几位网友在技术社区像Stack Overflow和知乎上的讨论,我总结了一下,主要有以下几种思路,你可以根据实际场景选一个最合适的。
第一个方法,也是最推荐的方法:利用Redis的键空间通知功能。
这个功能是Redis本身提供的,它的原理很简单:当Redis中的某个键因为过期而被删除时,或者被删除、被更新时,它可以发布一个通知到指定的频道里,我们可以订阅这个频道,就能知道哪个键什么时候没了。

具体到我们找“快过期”键的需求,我们可以这样变通一下:我们并不监听键的真正过期事件,而是监听键的“设置过期时间”的事件,Redis键空间通知里有一个事件叫做expire,当给一个键设置了过期时间时,这个事件就会被触发,一位名叫“antirez”的用户(他正是Redis的创始人)在GitHub的一个issue里解释过这些事件类型。
操作步骤大概是:
- 你得在Redis的配置文件里开启键空间通知功能,通常是设置
notify-keyspace-events这个参数,要监听过期相关事件,可以把它设为Ex(E表示启用键空间事件,x表示监听过期事件)。 - 你的应用程序可以像一个订阅者一样,连接到Redis集群的每个节点(因为键可能在任何节点上被设置过期时间),订阅一个特定的频道,
__keyspace@0__:*,这个频道会收到所有关于数据库0的键事件。 - 当有客户端执行了
EXPIRE、SETEX等命令给一个键设置过期时间时,你的订阅者就会立刻收到一个消息,告诉你“哪个键”被设置了过期时间,以及“它的过期时间戳是多少”。
这样一来,你就相当于有了一份实时的“待过期键清单”,你可以把这个信息记录到你自己搭建的一个外部数据库里(比如MySQL,甚至一个内存中的Map),之后,你想找哪些键快过期了,就不用去扫描整个Redis集群了,直接在你自己的这个清单数据库里查询就行了,比如查询“未来5分钟内要过期的键”,这个方法非常省资源,因为是事件驱动的,Redis只在有事发生时才发消息,平时不消耗额外性能,缺点是需要在应用侧维护一个额外的存储,并且要处理好集群每个节点的连接和订阅。
第二个方法,比较直接但需要谨慎使用:编写脚本分批扫描。

这个方法就是直面问题,既然集群是分布的,那我就一个一个节点去扫,很多运维朋友在论坛里提到他们实际上就是这么干的,虽然听起来有点“笨”,但在键数量不是特别巨大,且扫描频率不高的情况下(比如一天一次),是可行的。
你需要做的是:
- 写一个脚本(比如用Python的
redis-py-cluster库,或者Shell脚本结合redis-cli)。 - 这个脚本首先获取到Redis集群的所有主节点地址。
- 然后依次连接到每个节点上,在该节点上执行
SCAN命令遍历所有的键,这里千万不能用KEYS *命令,那个会阻塞Redis,在生产环境是禁止使用的。SCAN命令是游标方式的,不会阻塞服务。 - 对于
SCAN出来的每一个键,用TTL命令查看它剩余的生存时间。 - 如果TTL的值大于0(表示有过期时间)且小于你设定的阈值(比如300秒,也就是5分钟),你就把这个键名记录下来。
这个方法的好处是简单明了,不需要额外的组件和配置,结果准确,坏处也非常明显:它对Redis集群有性能影响,扫描整个集群的所有键是一项重量级操作,会消耗Redis服务器的CPU和网络带宽,如果键的数量达到百万、千万级别,扫描一次可能需要几十秒甚至更长时间,这段时间内会对正常服务造成压力,这种方法绝对不能在业务高峰期使用,最好在凌晨等低峰期定时执行。
第三个方法,是从源头下手:在业务代码里打点记录。

这个方法要求你对设置过期时间的业务代码有控制权,其核心思想是,既然键是你们业务程序设置的,那么在设置过期时间的那一刻,程序自己最清楚这个键会在什么时候过期。
你可以在业务代码里加一些逻辑:每当成功执行一个设置带过期时间的键值对的操作后(比如调用setex方法后),同时把这个键名和它的过期时间戳写入到一个集中的地方,比如可以写入到一个特定的Redis列表(List)或有序集合(Sorted Set)中,当然这个存储结构最好放在一个独立的、非集群的Redis实例里,以免影响业务集群。
- 如果用有序集合(ZSet),可以把过期时间戳作为分数(score),键名作为成员(member),这样,你随时想找快过期的键,只需要用
ZRANGEBYSCORE命令查询当前时间戳到“当前时间+阈值”这个范围内的所有成员就行了,效率极高。 - 如果用一个简单的列表,可以按过期时间顺序插入,然后定期检查列表头部的元素是否快过期了。
这个方法是最精准、对Redis集群性能影响最小的,因为它完全绕开了扫描,但它的缺点是侵入性强,需要修改所有涉及设置过期时间的业务代码,如果项目很庞大,改起来工作量不小,而且容易遗漏,如果有些键是通过Lua脚本或者别的途径设置的,可能就记录不到了。
- 想省事且对实时性要求高,优先考虑键空间通知方案,这是一劳永逸的办法。
- 只是偶尔需要检查一下,比如做容量规划或者故障排查,并且能接受在业务低峰期操作,可以用脚本扫描的方法,临时用一下。
- 如果你的团队能协调,并且追求最佳实践,那么业务代码打点是最优雅、最高效的解决方案。
最后提醒一点,无论用哪种方法,找到这些快过期的键之后,你要做什么很重要,如果只是监控和报警,那没问题,如果你想在它们过期前主动删除或更新它们,一定要非常小心,确保这个操作不会影响业务的正常逻辑,因为Redis的过期淘汰本身就是一个核心机制,胡乱干预可能会引来意想不到的问题。
本文由太叔访天于2025-12-28发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/69752.html
