Redis过期策略
个人博客
Redis深入学习之数据持久化
Redis深入学习之5种基本数据类型
Redis深入学习之数据持久化
前言
我们都知道Redis是一个键值对内存数据库,我们设置键值对时,可以对键值对设置超时时间。所以那些过期了的键值对就需要一种清理策略来清理。需要清理的场景主要有两种,一种是Redis那些设置了超时时间并且已经超时的键值对,此时的键值对失效了需要被清理,这种场景会采用定时删除+惰性删除的策略来清理。另外一种是由于Redis配置的内存已经到达上限,需要对那些过期或者还没过期的键值对按照内存淘汰策略进行清理,释放部分内存。
Redis之所以要采用这几种过期策略。主要因为 Redis 是单线程的,清理键值对的时间也会占用线程的处理时间,如果清理的太过于繁忙,将会导致线上读写指令出现卡顿。
定时删除
redis 会将每个设置了过期时间的 key 放入到一个独立的字典中,以后会定时遍历这个字典来删除到期的 key。Redis 默认会每秒进行十次过期扫描,过期扫描不会遍历过期字典中所有的 key,而是采用了一种简单的贪心策略。
- 从过期字典中随机 20 个 key;
- 删除这 20 个 key 中已经过期的 key;
- 如果过期的 key 比率超过 1/4,那就重复步骤 1;
同时,为了保证过期扫描不会出现循环过度,导致线程卡死现象,算法还增加了扫描时间的上限,默认不会超过 25ms。
从库的过期策略
这里从库需要特别说明下,从库不会进行过期扫描,从库对过期的处理是被动的。主库在 key 到期时,会在 AOF 文件里增加一条 del
指令,同步到所有的从库,从库通过执行这条 del
指令来删除过期的 key。
惰性删除
看了上面定时删除。肯定就会知道,定时删除会存在一个问题,定期删除可能会导致很多过期 key 到了时间并没有被删除掉,那咋整呢?
这就要用到惰性删除了。这就是说,在你获取某个 key 的时候,Redis 会检查一下 ,这个 key 如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。
内存淘汰机制
Redis经过上面的定时删除以及惰性删除还是有问题的,如果定期删除漏掉了很多过期 key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?可能会存在大量过期 key 堆积在内存里,将会导致 redis 内存块耗尽
这里说明下,在生产环境中我们是不允许 Redis 出现交换行为的,为了限制最大使用内存,Redis 提供了配置参数 maxmemory
来限制内存超出期望大小。针对上面的内存耗尽的问题,当实际内存超出 maxmemory
时,Redis 提供了几种可选策略 (maxmemory-policy) 来让用户自己决定该如何腾出新的空间以继续提供读写服务。
noeviction 不会继续服务写请求 (DEL 请求可以继续服务),读请求可以继续进行。这样可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略。
volatile-lru 尝试淘汰设置了过期时间的 key,最少使用的 key 优先被淘汰。没有设置过期时间的 key 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。
volatile-ttl 跟上面一样,除了淘汰的策略不是 LRU,而是 key 的剩余寿命 ttl 的值,ttl 越小越优先被淘汰。
volatile-random 跟上面一样,不过淘汰的 key 是过期 key 集合中随机的 key。
allkeys-lru 区别于 volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不只是过期的 key 集合。这意味着没有设置过期时间的 key 也会被淘汰(这种事最常用的)。
allkeys-random 跟上面一样,不过淘汰的策略是随机的 key。
volatile-xxx 策略只会针对带过期时间的 key 进行淘汰,allkeys-xxx 策略会对所有的 key 进行淘汰。如果你只是拿 Redis 做缓存,那应该使用 allkeys-xxx,客户端写缓存时不必携带过期时间。如果你还想同时使用 Redis 的持久化功能,那就使用 volatile-xxx 策略,这样可以保留没有设置过期时间的 key,它们是永久的 key 不会被 LRU 算法淘汰。
总结
Redis过期策略有三种,定时删除部分过期数据、惰性删除部分再次被访问的过期数据、基于内存淘汰策略淘汰部分数据。了解了Redis过期策略,有助于我们更好的理解Redis。
参考文章:过期策略