Redis-缓存淘汰与过期删除

过期删除策略和内存淘汰策略有什么区别?

  • 过期删除策略是将已过期的键值进行删除,Redis采用的删除策略是惰性删除和定时删除。
  • 内存淘汰策略是在内存满了的时候,redis触发内存淘汰策略,来淘汰一些不必要的内存资源,以腾出空间来保存新的内容。

Redis内存淘汰策略

在32位系统中,Redis的maxmemory默认值为3GB,这是因为32位系统最高支持4GB内存,而系统本身需要一定的内存资源来运行。为了避免因内存不足而导致Redis崩溃,设置maxmemory为3GB是一个合理的默认值。

Redis提供了8种内存淘汰策略,这些策略可以根据是否进行数据淘汰分为两类:

1. 不进行数据淘汰

  • noeviction(Redis 3.0之后默认使用的策略):当运行内存达到最大内存时,不会淘汰任何数据。如果有新的数据插入,Redis会返回错误。但对于普通的查询或删除操作,Redis可以正常运行。

2. 进行数据淘汰

针对“进行数据淘汰”这一类策略,又可以继续分为“在设置了过期时间的数据中淘汰”和“在所有数据范围内淘汰”两类。

“在设置了过期时间的数据中淘汰”:

  • volatile-random:随机淘汰设置了过期时间的数据。
  • volatile-ttl:优先淘汰过期时间最早的数据。
  • volatile-lru(Redis 3.0之前默认使用策略):淘汰所有设置了过期时间的数据中,最久未使用的键值。
  • volatile-lfu:淘汰所有设置了过期时间的数据中,最少使用的数据。

“在所有数据范围中进行淘汰”:

  • allkeys-random:随机淘汰任意键值
  • allkey-lru:淘汰整个键值中最久未使用的键值
  • allkeys-lfu:淘汰整个键值中最少使用的键值

Redis过期删除策略

Redis使用惰性删除定期删除相结合的过期删除策略,以在CPU使用时间和避免内存空间浪费之间取得平衡。

惰性删除

Redis的惰性删除策略由db.c文件中的expireIfNeeded函数实现。惰性删除的核心思想是:在访问或修改key之前,先检查key是否过期,如果过期则删除该key。

以下是expireIfNeeded函数源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
int expireIfNeeded(redisDb *db, robj *key) {
// 检查key是否设置了过期时间
if (!keyIsExpired(db,key)) return 0;

// 如果key过期,则删除该key
if (server.lazyfree_lazy_expire)
dbAsyncDelete(db,key);
else
dbSyncDelete(db,key);

// 返回1表示key已被删除
return 1;
}
  • 检查key是否过期:在访问或修改key之前,调用expireIfNeeded函数检查key是否过期。
  • 删除过期key:如果key过期,则根据lazyfree_lazy_expire参数配置,选择异步删除(dbAsyncDelete)或同步删除(dbSyncDelete)。
  • 返回结果:如果key过期并被删除,返回null给客户端;如果key未过期,则正常返回键值对给客户端。
惰性删除流程

定期删除

Redis的定期删除策略是每隔一段时间从内存中随机抽取一定数量的key进行检查,并删除其中过期的key。定期删除的目的是避免内存中积累过多的过期key,从而浪费内存空间。

定期删除的配置

  1. 间隔检查时间:默认是1秒检查10次,可以通过redis.conf文件进行配置。
  2. 随机抽查数量:在源码中,定期删除的实现在expire.c文件下的activeExpireCycle函数中,其中随机抽查的数量由ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP定义,数值是20。

定期删除的流程

  1. 随机抽取key:从过期字典中随机抽取20个key。
  2. 检查并删除过期key:检查这些key是否已过期,并删除已过期的key。
  3. 循环检查:如果本轮已过期的key超过5个,则继续抽取20个key再次进行检查删除,直到不满足该条件,退出。

Redis缓存为什么不过期直接删

在Redis中,过期key的删除策略是惰性删除和定期删除相结合的方式。然而,在内存不紧张但CPU紧张的情况下,Redis并不会立即删除过期的key,而是选择延迟删除。这种设计主要是为了在CPU资源紧张的情况下,优先保证业务性能,避免因频繁删除过期key而占用过多的CPU时间。