Redis 淘汰策略与过期策略及其应用场景

Posted 流楚丶格念

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis 淘汰策略与过期策略及其应用场景相关的知识,希望对你有一定的参考价值。

文章目录

今日单词:policy:策略

Redis的淘汰策略

当写入数据将导致超出maxmemory限制时,Redis会采用maxmemory-policy所指定的策略进行数据淘汰,该策略一共包含如下8种选项:

策略描述版本
noeviction直接返回错误;
volatile-ttl从设置了过期时间的键中,选择过期时间最小的键,进行淘汰;
volatile-random从设置了过期时间的键中,随机选择键,进行淘汰;
volatile-lru从设置了过期时间的键中,使用LRU算法选择键,进行淘汰;
volatile-lfu从设置了过期时间的键中,使用LFU算法选择键,进行淘汰;4.0
allleys-random从所有的键中,随机选择键,进行淘汰;
allkeys-lru从所有的键中,使用LRU算法选择键,进行淘汰;
allkeys-lfu从所有的键中,使用LFU算法选择键,进行淘汰;4.0

其中,volatile前缀代表从设置了过期时间的键中淘汰数据,allkeys前缀代表从所有的键中淘汰数据。
关于后缀,ttl代表选择过期时间最小的键,random代表随机选择键,需要我们额外关注的是lru和lfu后缀,它们分别代表采用lru算法和lfu算法来淘汰数据。

LRU(Least Recently Used)是按照最近最少使用原则来筛选数据,即最不常用的数据会被筛选出来

  • 标准LRU:把所有的数据组成一个链表,表头和表尾分别表示MRU(Max Recently Used)和LRU(Least Recently Used)端,即最常使用端和最少使用端。刚被访问的数据会被移动到MRU端,而新增的数据也是刚被访问的数据,也会被移动到MRU端。当链表的空间被占满时,它会删除LRU端的数据。

  • 近似LRU:Redis会记录每个数据的最近一次访问的时间戳(LRU)。Redis执行写入操作时,若发现内存超出maxmemory,就会执行一次近似LRU淘汰算法。近似LRU会随机采样N个key,然后淘汰掉最旧的key,若淘汰后内存依然超出限制,则继续采样淘汰。可以通过maxmemory_samples配置项,设置近似LRU每次采样的数据个数,该配置项的默认值为5

LRU算法的不足之处在于,若一个key很少被访问,只是刚刚偶尔被访问了一次,则它就被认为是热点数据,短时间内不会被淘汰

LFU算法正式用于解决上述问题,LFU(Least Frequently Used)是Redis4新增的淘汰策略,它根据key的最近访问频率进行淘汰。LFU在LRU的基础上,为每个数据增加了一个计数器,来统计这个数据的访问次数当使用LFU策略淘汰数据时,首先会根据数据的访问次数进行筛选,把访问次数最低的数据淘汰出内存。如果两个数据的访问次数相同,LFU再比较这两个数据的访问时间,把访问时间更早的数据淘汰出内存

Redis的过期策略

Redis支持如下两种过期策略:

  • 惰性删除:客户端访问一个key的时候,Redis会先检查它的过期时间,如果发现过期就立刻删除这个key。
  • 定期删除:Redis会将设置了过期时间的key放到一个独立的字典中,并对该字典进行每秒10次的过期扫描,过期扫描不会遍历字典中所有的key,而是采用了一种简单的贪心策略。该策略的删除逻辑如下:
    1. 从过期字典中随机选择20个key
    2. 删除这20个key中已过期的key
    3. 如果已过期key的比例超过25%,则重复步骤1

那么我们应如何合理的设置过期时间

  1. 热点数据不设置过期时间,使其达到“物理”上的永不过期,可以避免缓存击穿问题
  2. 在设置过期时间时,可以附加一个随机数,避免大量的key同时过期,导致缓存雪崩

缓存穿透、缓存击穿、缓存雪崩有什么区别,该如何解决?

缓存穿透:

问题描述:

客户端查询根本不存在的数据,使得请求直达存储层,导致其负载过大,甚至宕机。出现这种情况的原因,可能是业务层误将缓存和库中的数据删除了,也可能是有人恶意攻击,专门访问库中不存在的数据。

解决方案:

  1. 缓存空对象:存储层未命中后,仍然将空值存入缓存层,客户端再次访问数据时,缓存层会直接返回空值。
  2. 布隆过滤器:将数据存入布隆过滤器,访问缓存之前以过滤器拦截,若请求的数据不存在则直接返回空值。

缓存击穿:

问题描述:

一份热点数据,它的访问量非常大。在其缓存失效的瞬间,大量请求直达存储层,导致服务崩溃

解决方案:

  1. 永不过期:热点数据不设置过期时间,所以不会出现上述问题,这是“物理”上的永不过期。或者为每个数据设置逻辑过期时间,当发现该数据逻辑过期时,使用单独的线程重建缓存。
  2. 加互斥锁:对数据的访问加互斥锁,当一个线程访问该数据时,其他线程只能等待。这个线程访问过后,缓存中的数据将被重建,届时其他线程就可以直接从缓存中取值。

缓存雪崩:

问题描述:

在某一时刻,缓存层无法继续提供服务,导致所有的请求直达存储层,造成数据库宕机。可能是缓存中有大量数据同时过期,也可能是Redis节点发生故障,导致大量请求无法得到处理。

解决方案:

  1. 避免数据同时过期:设置过期时间时,附加一个随机数,避免大量的key同时过期。
  2. 启用降级和熔断措施:在发生雪崩时,若应用访问的不是核心数据,则直接返回预定义信息/空值/错误信息。或者在发生雪崩时,对于访问缓存接口的请求,客户端并不会把请求发给Redis,而是直接返回。
  3. 构建高可用的Redis服务:采用哨兵或集群模式,部署多个Redis实例,个别节点宕机,依然可以保持服务的整体可用。

以上是关于Redis 淘汰策略与过期策略及其应用场景的主要内容,如果未能解决你的问题,请参考以下文章

Redis的缓存淘汰策略LRU与LFU

RedisRedis经典9问—持久化/过期策略/缓存穿透/数据结构/事务/淘汰策略/应用场景/分布式锁

Redis 键的过期删除策略及缓存淘汰策略

Redis中的LRU淘汰策略分析

Redis过期删除策略和内存淘汰策略

Redis淘汰策略