Redis 的过期策略

在日常开发中,我们使用Redis存储key时通常会设置一个过期时间,但是Redis是怎么删除过期的key,而且Redis是单线程的,
删除Key会不会造成阻塞。要搞清楚这些,就要了解Redis的过期策略和内存淘汰机制。

Redis采用的是定期删除 + 懒惰删除策略。

定期删除策略

Redis会将每个设置了过期时间的key放入到一个独立的字典中,默认每100ms进行一次过期扫描:

  1. 随机抽取20key
  2. 删除这20key中过期的key
  3. 如果过期的key比例超过1/4,就重复步骤1,继续删除。

为什不扫描所有的keyRedis是单线程,全部扫描岂不是卡死了。
而且为了防止每次扫描过期的key比例都超过1/4,导致不停循环卡死线程,Redis为每次扫描添加了上限时间,默认是25ms

如果在同一时间出现大面积key过期,Redis循环多次扫描过期词典,直到过期的key比例小于1/4。这会导致卡顿,而且在高并发
的情况下,可能会导致缓存雪崩

为什么Redis为每次扫描添的上限时间是25ms,还会出现上面的情况?
因为Redis是单线程,每个请求处理都需要排队,而且由于Redis每次扫描都是25ms,也就是每个请求最多25ms,100 个请求就是2500ms

懒惰删除策略

懒惰删除策略就是指,在访问某个key时,Redis判断key是否过期,过期了就删除。定期删除是集中处理,惰性删除是零散处理。

内存淘汰机制

Redis的内存占用会越来越高。Redis为了限制最大使用内存,提供了redis.conf中的
配置参数maxmemory。当内存超出maxmemoryRedis提供了几种内存淘汰机制让用户选择,配置maxmemory-policy

  • noeviction:当内存超出maxmemory,写入请求会报错,但是删除和读请求可以继续。(使用这个策略,疯了吧)
  • allkeys-lru:当内存超出maxmemory,在所有的key中,移除最少使用的key。只把Redis既当缓存是使用这种策略。(推荐)。
  • allkeys-random:当内存超出maxmemory,在所有的key中,随机移除某个 Key。(应该没人用吧)
  • volatile-lru:当内存超出maxmemory,在设置了过期时间key的字典中,移除最少使用的key。把Redis既当缓存,又做持久化的时候使用这种策略。
  • volatile-random:当内存超出maxmemory,在设置了过期时间key的字典中,随机移除某个key
  • volatile-ttl:当内存超出maxmemory,在设置了过期时间key的字典中,优先移除ttl小的。

近似 LRU 算法

Redis使用的并不是完全LRU算法。不使用LRU算法,是为了节省内存,Redis采用的是随机LRU算法,Redis为每一个key增加了一个24 bit的字段,
用来记录这个key最后一次被访问的时间戳。注意RedisLRU淘汰策略是懒惰处理,也就是不会主动执行淘汰策略,当Redis执行写操作时,发现内存超出maxmemory
就会执行LRU淘汰算法。这个算法就是随机采样出5(默认值)个key,然后移除最旧的key,如果移除后内存还是超出maxmemory,那就继续随机采样淘汰,直到内存低于maxmemory为止。
随机采样的key的个数可以通过参数maxmemory-samples配置。