文章首发于公众号:蘑菇睡不着,欢迎来看看
Redis 中都是键值对的存储形式,键都是字符串类型的,而值有很多种类型,如 string、list、hash、set、sorted set等类型。当设置键值对时我们还应该为其设置过期时间,通过 expire 以及 pexpire 命令;还可以通过 setnx 命令设置。那么,当设置过期时间之后,到底是怎么将过期的键值对删除的那?想知道答案的话,我们就一起看看 Redis 的过期键删除策略。
在说删除策略之前有个点带大家先了解下,那就是如果确定一个键是否过期,这里我总结了下:
以上就是判断一个键是否过期的方法。接下来说说当键过期了怎么去删除。
目前来说有三种删除策略:
下面来详细介绍每一种删除策略。
定时删除策略
优点是:对内存友好。因为通过定时器,当一个键到达过期时间时就会立马被删除,直接就释放了内存。
缺点是:对 CPU 不友好。因为如果过期键比较多,那么删除这些过期键会占用相当一部分CPU时间,如果CPU时间非常紧张的话,还将CPU时间用在删除和当前任务无关的过期键上,会对服务器的响应时间以及吞吐量造成影响。
因此,通过 定时删除 策略来时间过期键的删除不太现实。
惰性删除策略优点:对 CPU 时间友好。程序只会在取出键时才会判断是否删除,并且只作用到当前键上,其他过期键不会花费 CPU 时间去处理。
惰性删除策略缺点:对内存不友好。因为只有键被使用时才会去检查是否删除,如果有大量的键一直不被使用,那么这些键就算过期了也不会被删除,会一直占用着内存。这种可以理解为是一种内存泄漏——大量无用的数据一直占用着内存,并且不会被删除。
相比较定时删除对CPU的不友好,惰性删除的对内存不友好。定期删除采用了一种折中的方式:
但删除的时长和频率比较难定义,因为:
因此。如果采用定期删除策略的话需要通过具体的业务场景来定义时长和频率。
通过这两种方式可以很好的利用CPU时间以及避免内存浪费的情况。接下来讲讲惰性删除以及定期删除的实现。
惰性删除策略由 expireIfNeeded 函数实现,所有读写数据库的 Redis 命令在执行之前都会调用 exipreIfNeeded 函数对输入键进行检查。
定期删除策略由 activeExpireCucle 函数实现,被调用时,它在规定的时间内,分多次遍历服务器中的各个数据库,从数据库的 expires 字典中随机检查一部分键的过期时间,并删除其中的过期键。
在执行 SAVE 命令或 BGSAVE 命令创建一个新的 RDB 文件时,程序会对数据库中的键进行检查,已过期的键不会被保存到新的 RDB 文件中。
如:redis中包含 r1、r2、r3 三个键,并且 r1 已经过期,那么程序只会讲 r2 和 r3 保存到 RDB 文件中。
因此,过期键不会对新的 RDB 文件造成影响。
在启动 redis 服务器时,如果服务器开启了 RDB 功能,那么服务器将对 RDB 文件进行载入;
当服务器开启 AOF 的运行模式时,如果某个键过期了,但没有被惰性或定期删除,那么 AOF 不会理会。如果被惰性或定期删除了, AOF 会在文件末尾追加一条 DEL 命令,来显示地记录该键已被删除。
当 AOF 重写时,过期的键不会被载入到 redis 数据库中。
当服务器在 复制 模式下时,从服务器的过期键删除动作都是由主服务器来进行的。
Redis 的过期键删除策略是 惰性删除 + 定期删除,这也既可以合理的控制 CPU 使用 还可以 减少内存的浪费。
关于更多 Java 知识以及刷题分享,可以来公众号 蘑菇睡不着 看看,大家一起学习。
你越主动就会越主动,我们下期见~