Redis系列 - 过期策略和淘汰策略

提到内存管理,我们就需要考虑Redis的内存过期策略和内存淘汰机制。该文章便从这两方面入手,分享一些在Redis内存方面相关的基础知识。

内存过期策略

内存过期策略主要的作用就是,在缓存过期之后,能够及时的将失效的缓存从内存中删除,以减少内存的无效暂用,达到释放内存的目的。Redis内存过期策略分为三类,定时策略、惰性策略和定期策略。

定时策略

含义:在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除。

优点:保证内存被尽快释放,减少无效的缓存暂用内存。

缺点:若过期key很多,删除这些key会占用很多的CPU时间,在CPU时间紧张的情况下,CPU不能把所有的时间用来做要紧的事儿,还需要去花时间删除这些key。定时器的创建耗时,若为每一个设置过期时间的key创建一个定时器(将会有大量的定时器产生),性能影响严重。一般来说,是不会选择该策略模式。

惰性策略

含义:key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期,则删除,返回null。

优点:删除操作只发生在从数据库取出key的时候发生,而且只删除当前key,所以对CPU时间的占用是比较少的,而且此时的删除是已经到了非做不可的地步(如果此时还不删除的话,我们就会获取到了已经过期的key了)。

缺点:若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,此时的无效缓存是永久暂用在内存中的,那么可能发生内存泄露(无用的垃圾占用了大量的内存)。

定期策略

含义:每隔一段时间对设置了缓存时间的key进行检测,如果可以已经失效,则从内存中删除,如果未失效,则不作任何处理。

优点:通过限制删除操作的时长和频率,来减少删除操作对CPU时间的占用–处理”定时删除”的缺点。

缺点:在内存友好方面,不如”定时删除”,因为是随机遍历一些key,因此存在部分key过期,但遍历key时,没有被遍历到,过期的key仍在内存中。在CPU时间友好方面,不如”惰性删除”,定期删除也会暂用CPU性能消耗。

难点:合理设置删除操作的执行时长(每次删除执行多长时间)和执行频率(每隔多长时间做一次删除)(这个要根据服务器运行情况来定了)。

注意:该方式不是去遍历所有的key,而是随机抽取一些key做过期检测。

过期策略对持久化存储的影响

持久化存储,指的是将内存的缓存永久存在磁盘中。也就是说我们的AOF和RDB持久化存储方式。因为该两种方式,将内存中的数据写入磁盘,这时候就需要考虑到我们过期的缓存是否会被写入到磁盘中?如果写入磁盘又是怎么处理的?

RDB持久化
  • 持久化key之前,会检查是否过期,过期的key不进入RDB文件。

  • 数据载入数据库之前,会对key先进行过期检查,如果过期,不导入数据库(主库情况)。

AOF持久化
  • 当key过期后,还没有被删除,此时进行执行持久化操作(该key是不会进入AOF文件的,因为没有发生修改命令)。

  • 当key过期后,在发生删除操作时,程序会向AOF文件追加一条del命令(在将来的以AOF文件恢复数据的时候该过期的键就会被删掉)。

因为AOF方式,向存储文件追加的是Redis的操作命令,而不是具体的数据,然而RDB确是存储的安全的二进制内容。

  • 重写时,会先判断key是否过期,已过期的key不会重写到AOF文件。

即使在重写时,不验证是否过期,然而追加了del命令,测试无效的key同样会被删除。判断的情况是为了防止没有加入del命令的key。

Redis中主要使用 定期删除 + 惰性删除 两种数据过期清除策略:

  • 定期删除:redis默认每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果有过期就删除。注意这里是随机抽取的。为什么要随机呢?你想一想假如 redis 存了几十万个 key ,每隔100ms就遍历所有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载
  • 惰性删除:定期删除可能导致很多过期的key 到了时间并没有被删除掉。这时就要使用到惰性删除。在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间并且过期了,是的话就删除。

定期删除+惰性删除存在的问题:

  • 如果某个key过期后,定期删除没删除成功,然后也没再次去请求key,也就是说惰性删除也没生效。这时,如果大量过期的key堆积在内存中,redis的内存会越来越高,导致redis的内存块耗尽。那么就应该采用内存淘汰机制。

内存淘汰机制

内存淘汰机制针对是内存不足的情况下的一种Redis处理机制。例如,当前的Redis存储已经超过内存限制了,然而我们的业务还在继续往Redis里面追加缓存内容,这时候Redis的淘汰机制就起到作用了。

淘汰机制分类

根据redis.conf的配置文件中,我们可以得出,主要分为如下六种淘汰机制。

1
2
3
4
5
6
7
8
volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)。
volatile-lfu:当内存不足以容纳新写入数据时,在过期密集的键中,使用LFU算法进行删除key。
allkeys-lfu:当内存不足以容纳新写入数据时,使用LFU算法移除所有的key。
volatile-random:当内存不足以容纳新写入数据时,在设置了过期的键中,随机删除一个key。
allkeys-random:当内存不足以容纳新写入数据时,随机删除一个或者多个key。
volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。

通常情况下推荐优先使用 allkeys-lru 策略。这样可以充分利用 LRU 这一经典缓存算法的优势,把最近最常访问的数据留在缓存中,提升应用的访问性能。

如果你的业务数据中有明显的冷热数据区分,建议使用 allkeys-lru 策略。

如果业务应用中的数据访问频率相差不大,没有明显的冷热数据区分,建议使用 allkeys-random 策略,随机选择淘汰的数据就行。

如果没有设置过期时间的键值对,那么 volatile-lru,volatile-lfu,volatile-random 和 volatile-ttl 策略的行为, 和 noeviction 基本上一致。

Read More:

Redis的过期策略和内存淘汰策略最全总结与分析

Redis的数据过期清除策略 与 内存淘汰策略