Redis过期删除策略、内存淘汰策略详解

10 阅读6分钟

参考:小林coding

过期删除策略

在Redis中,我们可以对指定的key设置过期时间,因此也就需要相应的策略,将已过期的key-value删除,这个策略就称之为过期删除策略。

如何判定key是否过期?

每当我们对一个key设置了过期时间时,Redis会将这个key以及其过期时间对应的时间戳存储到一个过期字典中,这个过期字典保存了redis中所有key的过期时间。

我们知道一个redis节点可以分为0-15号数据库,每个数据库就是下面的一个redisDb结构:

typedef struct redisDb {
    dict *dict;/*数据库键空间,存放着所有的键值对*/
    dict*expires;/*键的过期时间*/
} redisDb;

过期字典中保存的key是一个指针,指向某个key对象。value是一个long long类型的整数,保存了过期时间对应的时间戳。

redisDb的结构如下图所示:

image.png

当我们查询一个key的时候,Redis首先会检查该key是否存在于过期字典中:

  • 如果不在,则正常读取value
  • 如果在,获取该key的过期时间,与当前时间进行比对,判断是否过期,未过期则返回,过期了则返回null。

常见的过期删除策略有哪些?

定时删除

在对每个key设置过期时间时,同时创建一个定时事件,当时间到达的时候,事件触发,key被删除。

定时删除策略可以确保过期的key被尽快删除,占用的内存被尽快释放,因此该策略对内存友好。但是在过期key比较多的情况下,删除过期key可能会占用相当一部分的CPU资源,在服务器的CPU资源紧张时,这会对Redis节点的响应时间和吞吐量造成影响,所以,该策略对CPU资源不友好。

惰性删除

不主动删除过期的key,每次从数据库中访问key时,才去检测key是否过期,如果过期则删除。

显然,因为只有每次访问时才可能会触发删除逻辑,所以惰性删除只会使用很少的CPU资源,所以该策略对CPU资源友好。但是如果一些key已经过期,但是又长期没有被访问,这些key所占用的内存就一直不会被释放,所以惰性删除策略对内存不友好。

定期删除

每隔一段时间随机从数据库中取出一定数量的key进行检查,并删除其中的过期key。

定期删除策略相对于定时删除来说,限制了删除操作执行的频率,防止了删除操作占用过多CPU资源;但是内存清理方面不如定时删除策略。

定期删除策略相对于惰性删除来说,能删除一部分过期数据,对内存更友好。但是相对来说占用了更多CPU资源。

但是在实际生产环境中,很难确定定期删除的频率和时长,如果执行的频率太低、每次执行的时长太短,内存不会得到及时释放,就和惰性删除没区别;如果执行的频率太高、每次执行的时长太长,就会占用太多CPU资源,就和定时删除没区别了。

Redis的过期删除策略是怎么样的?

惰性删除 + 定期删除。

Redis是如何实现惰性删除的呢?

当我们查询一个key的时候,Redis首先会检查该key是否存在于过期字典中:

  • 如果不在,则正常读取value
  • 如果在,获取该key的过期时间,与当前时间进行比对,判断是否过期,未过期则返回,过期了则返回null,并由lazyfree_lazy_expire参数配置决定异步删除还是同步删除。

Redis是如何实现定期删除的呢?

Redis默认每秒进行10次抽查,这个频率由redis.conf中的hz配置项决定,默认值是10。每次随机从过期字典中抽查20个key判断是否过期,具体流程如下:

1、从过期字段中随机抽取20个key 2、删除其中过期的key 3、如果本轮抽查中已过期key的数量占比超过随机抽取的key数量的25%,则重复进行一次定期删除。如果小于25%,则停止,等待下一轮定期删除。

Redis为了保证定期删除不会占用太多的CPU资源,为这个流程设置了时间上限,默认不超过25ms。

内存淘汰策略

当Redis占用的内存超过了给Redis设置的最大内存后,Redis就会使用内存淘汰策略删除部分key。

在redis.conf中,通过maxmemory <bytes>配置项可以配置允许Redis使用的最大内存。在64位操作系统中,该参数默认为0,表示没有内存限制;在32位操作系统中,maxmemory默认为3GB,因为32位操作系统最大只支持4GB的内存,系统本身也需要一定的内存来支持运行,所以限制为3G也是比较合理的。

Redis的内存淘汰策略有哪些?

Redis的内存淘汰策略共有八种,可以分为不淘汰数据以及淘汰数据两类,在淘汰数据的类型中,又分为在设置了过期时间的数据中淘汰、在所有数据中进行淘汰两类。

不淘汰数据

noevction:当redis占用的内存超过最大内存配置时,不淘汰任何数据,此时如果有新的数据写入,则直接给客户端返回报错。但是只是正常的查询或是删除操作,还是可以正常工作的。

淘汰数据

在设置了过期时间的数据中进行淘汰:

  • volatile-random:随机淘汰设置了过期时间的数据
  • volatile-ttl:优先淘汰剩余存活时间较短的数据
  • volatile-lru:在所有设置了过期时间的数据中,淘汰最久未使用的数据
  • volatile-lfu:在所有设置了过期时间的数据中,淘汰最少使用的数据

在所有数据中淘汰:

  • allkeys-random:随机淘汰任意数据
  • allkeys-lru:淘汰最久未使用的数据
  • allkeys-lfu:淘汰最少使用的数据

LRU和LFU有什么区别?