Redis里多线程怎么管过期数据,感觉挺复杂又有点乱的实现思路
- 问答
- 2025-12-25 19:01:11
- 1
Redis处理过期数据这个事,确实不像表面看起来那么简单,它内部有一套组合拳,不是单靠一种方法搞定,感觉乱,可能是因为它为了平衡性能和内存使用,用了好几种策略协同工作,咱们就把它拆开揉碎了说,主要就是三个方面:被动删除、主动清理和内存不够时的强制驱逐,这些都是根据《Redis设计与实现》这本书以及Redis官方文档中的相关描述来梳理的。
第一招:懒人方法——被动删除
这是最简单直接,也是性能最好的方式,核心思想就是“用到的时候才检查它过没过期”,当你用一个命令去访问某个键的时候,GET user:1001,Redis在查找这个键的值之前,会先偷偷地检查一下这个键是否设置了过期时间,并且是否已经过期了。
如果发现这个键已经过期了,Redis会立刻把这个键值对删掉,然后当做这个键从来没存在过一样,返回一个空值给客户端,这个操作是在处理你这条命令的那个线程里同步完成的,你看,这个方法很巧妙,它把删除过期键的成本分摊到了每一个可能会触发这个操作的客户端请求上,对于那些再也没被访问过的过期键,它就不管了吗?也不是,这就引出了第二招。
第二招:定期抽查——主动清理
光靠被动删除不行,万一有些键设置了过期时间,但之后再也没人访问它,那它们就会一直赖在内存里,变成“垃圾数据”,所以Redis必须得主动出击,定期去扫一扫,清理掉这些“僵尸键”。
这个主动清理的过程,Redis是用一个叫“定时任务”的机制来做的,但这个定时任务很聪明,它知道不能一次性扫描所有键,那样会卡住整个服务器,导致一段时间内无法响应客户端的请求,这叫“阻塞”,它采用的是一种渐进式的、分批扫描的策略。

Redis会每隔一段时间(默认是100毫秒,这个时间很短,用户几乎感觉不到)就运行一次这个清理任务,每次任务不会贪多,而是有节制地做以下几件事:
- 随机抽检: 从设置了过期时间的键的集合里,随机抽取一定数量的键(比如默认抽20个)。
- 检查并删除: 挨个检查这些被抽中的键,如果过期了,就删掉。
- 控制时长: 在抽查和删除的过程中,它会一直计算自己花了多少时间,如果发现本次任务已经用了太长时间(比如超过了预设的CPU时间上限),即使还没抽查完预设的数量,它也会立刻停下来,保证不会长时间阻塞系统,剩下的活留给下一次定时任务再做。
这个过程是穿插在Redis处理正常请求的间隙中进行的,像蚂蚁搬家一样,一点一点地把过期数据清理掉,因为是随机抽查,所以可能不会一次就清理得非常干净,但它保证了整个服务的响应速度,这是一种在清理彻底性和性能之间做的权衡。
第三招:最后防线——内存驱逐
前面两招是常规操作,但万一数据量特别大,过期键产生的速度比清理的速度还快,或者系统内存本来就不多了,这时候内存可能就会不够用,Redis有一个配置项叫 maxmemory,可以设置最大使用内存,当实际内存使用达到这个上限时,就会触发“内存驱逐”机制。

这时候,Redis就不是只盯着过期键了,它要根据你预设的淘汰策略来决定牺牲掉哪些数据来腾出空间,常见的策略有:
volatile-lru:在所有设置了过期时间的键中,淘汰最近最少使用的。allkeys-lru:在所有键中(不管设没设过期时间),淘汰最近最少使用的。volatile-random:在所有设置了过期时间的键中,随机淘汰一个。allkeys-random:在所有键中,随机淘汰一个。volatile-ttl:在所有设置了过期时间的键中,淘汰剩余存活时间最短的。
注意,volatile-ttl 这个策略就和过期时间强相关了,它会优先把那些马上就要过期的键踢出去,算是一种比较优雅的清理方式,内存驱逐这个动作,是发生在有新的命令需要分配内存(比如写入新数据),但发现内存不足时,由执行该命令的线程同步触发的,这相当于一道紧急闸门,防止内存被彻底撑爆。
多线程的参与(Redis 6.0之后)
你提到多线程,这里需要澄清一下,在Redis 6.0版本之前,上面说的所有这些操作——处理网络I/O、执行命令(包括被动删除)、运行定时任务(主动清理)、执行内存驱逐——都是由同一个主线程来串行处理的,所以不存在多线程管理过期数据的复杂性问题,因为都是单线程干的,天然就不会有并发冲突。
从Redis 6.0开始,它引入了多线程,不过这个多线程仅仅用于处理网络I/O,也就是读取客户端请求数据和写回响应数据,而最核心的命令解析和执行(其中就包含了被动删除和内存驱逐),以及定时任务(主动清理),依然是由那个唯一的主线程来负责的。
结论是:管理过期数据(被动删除、主动清理、内存驱逐)的逻辑本身,在Redis中仍然是单线程执行的,这样做的好处是,完全避免了多线程环境下,同时读写数据可能带来的竞态条件和锁的开销,简化了实现,保证了原子性,你感觉到的“复杂又有点乱”,其实不是多线程并发控制带来的乱,而是它那套为了高性能而设计的、多种策略混合并协同工作的机制本身需要仔细理解,它通过被动、主动、强制这三层保障,在大多数场景下都能高效且自动地管理好过期数据。
本文由寇乐童于2025-12-25发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/68331.html
