Redis之缓存穿透击穿雪崩问题与缓存删除淘汰策略

Posted 丨Jack_Chen丨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis之缓存穿透击穿雪崩问题与缓存删除淘汰策略相关的知识,希望对你有一定的参考价值。

一、缓存问题与解决

缓存穿透

缓存穿透是指查询缓存和DB中都不存在的数据

缓存穿透示例:

    public Station findProjectStation(Long stationId) 
        //从缓存中查询
        Station station = (Station)redisTemplate.boundHashOps("project_station").get(stationId);
        if(station==null)
            //缓存中没有,从数据库查询
            Station st = stationMapper.selectByPrimaryKey(stationId);
            if(st!=null) 
                station = st;
                redisTemplate.boundHashOps("project_station").put(stationId,station);
            
        
        return station;
    

解决方案:

​1.接口层增加校验,如鉴权校验

2.id做校验,id<=0的直接拦截;

​3.从缓存取不到的数据,在数据库中也没有取到,就将key-value对写为key-空对象。以此防止攻击者反复用同一个id暴力攻击。

4. 使用缓存预热,缓存预热就是将数据提前加入到缓存中,当数据发生变更,再将最新的数据更新到缓存。

5. 利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试

6. 利用布隆过滤器,内部维护一系列合法有效的key。迅速判断出,请求所携带的Key是否合法有效。如果不合法,则直接返回

解决缓存穿透示例:

    public Station findProjectStation(Long stationId) 
        //从缓存中查询
        Station station = (Station)redisTemplate.boundHashOps("project_station").get(stationId);
        if(station==null)
            //缓存中没有,从数据库查询
            Station st = stationMapper.selectByPrimaryKey(stationId);
            if(st!=null)
                station = st;
                redisTemplate.boundHashOps("project_station").put(stationId,station);
            else 
                redisTemplate.boundHashOps("project_station").put(stationId,new Station());
                redisTemplate.boundHashOps("project_station").expire(60, TimeUnit.SECONDS);
            
        
        return station;
    

缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据

可能产生缓存击穿示例:

    public List<Station> findStationList() 
        //从缓存中查询
        List<Station> stationList = (List<Station>)redisTemplate.boundValueOps("station_list").get();;
        if(stationList==null)
            //缓存中没有,从数据库查询
            Example example=new Example(Station.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("type","1");
            List<Station> findStationList = stationMapper.selectByExample(example);
            if(findStationList!=null)
                stationList = findStationList;
                redisTemplate.boundValueOps("station_list").set(stationList);
            
        
        return stationList;
    

解决方案:

​1.设置热点数据永远不过期。

​2.缓存预热

3.数据不设置过期时间,在缓存的对象上添加一个属性标识过期时间,每次获取到数据时,校验对象中的过期时间属性,如果数据即将过期,则异步发起一个线程主动更新缓存中的数据,当然也可能拿到过期的值,看具体需求。

缓存雪崩

缓存雪崩是指缓存数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至宕机

解决方案:

​1.缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。如果Redis是集群部署,将热点数据均匀分布在不同的Redis库中也能避免全部失效的问题

​2.设置热点数据永远不过期。

​3.使用缓存预热

4.使用互斥锁,但是该方案将导致吞吐量明显下降

三者区别

缓存穿透:通常请求携带有参数,不断发起请求。

缓存击穿:通常是某个时刻并发大量请求,并发查询同一条数据。

缓存雪崩:缓存不同的数据大批量到过期时间,很多数据都查不到从而查数据库。

缓存预热

实现缓存预热方法:

@Component
public class RedisInit implements InitializingBean

@Autowired
private IStationService stationService;

/**
 * 缓存预热
 *
 * @throws Exception
 */
@Override
public void afterPropertiesSet() throws Exception 
    stationService.saveStationListToRedis();



# 二、缓存淘汰机制
>Redis可以对存储在Redis中的缓存数据设置过期时间,但是并非key过期时间到了就一定会被Redis给删除。

Redis可以设置最大缓存即最大内存,当内存已使用率到达,则开始清理缓存

    maxmemory <bytes> :设置最大内存 maxmemory 500mb
## 删除策略
>设置了expire的key缓存过期了,但是服务器的内存还是会被占用,这是因为redis是基于删除策略进行删除

Redis删除策略主要有三种:

1.定期删除

>Redis默认是每隔 100ms 就随机抽取一些设置了过期时间的 Key,检查其是否过期,如果过期就删除。

2.惰性删除

>定期删除由于是随机抽取可能会导致很多过期 Key 到了过期时间并没有被删除。在从缓存获取数据的时候,redis会检查这个key是否过期了,如果过期就删除这个key。也就是说在查询的时候将过期key从缓存中清除。

3.主动删除

>当内存满了,依据配置的淘汰策略进行删除

## 内存淘汰机制
>仅使用定期删除 + 惰性删除机制存在一个严重的隐患:如果定期删除留下了很多已经过期的key,并且长时间都没有使用过这些过期key,会导致过期key无法被惰性删除,从而导致过期key一直堆积在内存里,最终造成Redis内存块被消耗殆尽。

Redis内存淘汰机制应运而生。Redis内存淘汰机制提供了八种不同的内存淘汰策略,4.0前有6种。

    volatile-lru : 从已设置过期时间的缓存中,淘汰最近最少使用的数据,推荐使用策略

    volatile-ttl: 在设置了过期时间的缓存中,挑选将要过期的数据,直接淘汰

    volatile-random: 从已设置过期时间的缓存中,随机淘汰数据

    allkeys-lru: 所有数据,淘汰最近最少使用的,即清除最少用的旧缓存,然后保存新的缓存,推荐使用

    allkeys-random: 在所有的缓存中随机删除,不推荐

    noeviction: 旧缓存永不过期,新缓存设置不了,不淘汰,内存满了返回错误,默认策略

    volatile-lfu: 从已设置过期时间的缓存中,淘汰使用频率最低的数据

    allkeys-lfu: 所有数据,淘汰使用频率最低的数据

以上是关于Redis之缓存穿透击穿雪崩问题与缓存删除淘汰策略的主要内容,如果未能解决你的问题,请参考以下文章

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

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

Redis缓存穿透击穿雪崩到底是个啥?7张图告诉你

Redis

Redis的缓存问题之缓存穿透缓存雪崩缓存击穿

Redis——缓存穿透缓存击穿缓存雪崩分布式锁