Redis过期策略底层是如何实现的?

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!
Redis过期策略底层是如何实现的?

过期策略

如果我们对key设置了失效时间1分钟,1分钟后,Redis 是如何对这个 key 进行删除的呢?

Redis过期策略采用的是惰性删除+定期删除策略。

Redis过期策略底层是如何实现的?

惰性删除

当某个key被设置了过期时间之后,客户端每次对该key的访问(读写)都会事先检测该key是否过期,如果过期就直接删除。

Redis过期策略底层是如何实现的?

定期删除

当某个key被设置了过期时间之后,客户端每次对该key的访问(读写)都会事先检测该key是否过期,如果过期就直接删除(这种是被动删除);但有一些键只访问一次或者是冷数据,因此需要主动删除,默认情况下Redis每秒检测10次,检测的对象是所有设置了过期时间的键集合,每次从这个集合中随机检测20个键查看他们是否过期,如果过期就直接删除,如果过期的key比例超过1/4,那就把上述操作重复一次(贪心算法)。同时为了保证过期扫描不会出现循环过度,导致线程卡死现象,算法还增加了扫描时间的上限,默认不会超过25ms。

如果一个大型的 Redis 实例中所有的 key 在同一时间过期了,会引发什么问题?

这个主动过期 key 的定时任务,是在 Redis 主线程中执行的,也就是说如果在执行主动过期的过程中,出现了需要大量删除过期 key 的情况,那么此时应用程序在访问 Redis 时,必须要等待这个过期任务执行结束,Redis 才可以服务这个客户端请求。此时就会出现,应用访问 Redis 延时变大。

有小伙伴问,扫描不是有 25ms 的时间上限了么,怎么会导致卡顿呢?

假如有 1001 个客户端同时将请求发过来了,然后前 1000 个请求的执行时间都是 25ms,那么第 1001 个指令需要等待多久才能执行?25000ms,25秒,这个就是客户端的卡顿时间,是由服务器不间断的小卡顿积少成多导致的。

大量key集中过期导致卡顿如何解决?

方案一:在设置 key 的过期时间时,增加一个随机时间

redis.expireat(key, expire_time + random(300))

这样一来,Redis 在处理过期时,不会因为集中删除过多的 key 导致压力过大,从而避免阻塞主线程。

方案二:Redis 4.0 以上版本,开启 lazy-free 机制

lazyfree-lazy-expire yes

另外,除了业务层面的优化和修改配置之外,你还可以通过运维手段及时发现这种情况。

运维层面,你需要把 Redis 的各项运行状态数据监控起来,在 Redis 上执行 INFO 命令就可以拿到这个实例所有的运行状态数据。

在这里我们需要重点关注 expired_keys 这一项,它代表整个实例到目前为止,累计删除过期 key 的数量。

你需要把这个指标监控起来,当这个指标在很短时间内出现了突增,需要及时报警出来,然后与业务应用报慢的时间点进行对比分析,确认时间是否一致,如果一致,则可以确认确实是因为集中过期 key 导致的延迟变大。

从库的过期策略:从库不会进行过期扫描,从库对过期的处理是被动的。主库在 key 到期时,会在 AOF 文件里增加一条 del 指令,同步到所有的从库,从库通过执行这条 del 指令来删除过期的 key。

原文始发于微信公众号(Java程序鱼):Redis过期策略底层是如何实现的?