redis缓存雪崩缓存击穿缓存穿透解决方案(代码片段)

你携秋月揽星河丶 你携秋月揽星河丶     2023-02-04     471

关键词:

1 缓存雪崩

1.1 发生原因

(1) Redis主机挂了,Redis缓存全部失效。
(2) 当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。

1.2 解决思路

(1) Redis实现高可用。
(2) 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
(3) 限流&降级。

2 缓存击穿

2.1 发生原因

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。

2.2 解决思路

多个线程同时去查询数据库的这条数据,那么我们可以在第一个查询数据的请求上使用一个 互斥锁来锁住它。其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后做缓存。后面的线程进来发现已经有缓存了,就直接走缓存。

@Service
public class StudentService 

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private StudentMapper studentMapper;

    private final Object lock = new Object();

    public Student getStudent(Long id) 

        //读取redis,存在直接返回
        String s = redisTemplate.opsForValue().get(String.valueOf(id));
        if (StringUtils.isNotBlank(s)) 
            return JSON.parseObject(s, Student.class);
        
        //并行变成串行
        synchronized (lock) 
            //读取redis,存在直接返回
            String str = redisTemplate.opsForValue().get(String.valueOf(id));
            if (StringUtils.isNotBlank(str)) 
                return JSON.parseObject(str, Student.class);
            
            //从数据库读取存入redis中
            Student student = studentMapper.findOne(id);
            redisTemplate.opsForValue().set(String.valueOf(id), JSON.toJSONString(student), 7, TimeUnit.DAYS);
            return student;
        

    

3 缓存穿透

3.1 起因

key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。

3.2 解决思路

布隆过滤器

3.3 布隆过滤器

布隆过滤器(英语:Bloom Filter)是 1970 年由布隆提出的。
它实际上是一个很长的二进制数组+一系列随机hash算法映射函数,主要用于判断一个元素是否在集合中。

通常我们会遇到很多要判断一个元素是否在某个集合中的业务场景,一般想到的是将集合中所有元素保存起来,然后通过比较确定。
链表、树、散列表(又叫哈希表,Hash table)等等数据结构都是这种思路。

但是随着集合中元素的增加,我们需要的存储空间也会呈现线性增长,最终达到瓶颈。同时检索速度也越来越慢,上述三种结构的检索时间复杂度分别为O(n),O(logn),O(1)。这个时候,布隆过滤器(Bloom Filter)就应运而生

3.3.1 添加

当我们向布隆过滤器中添加数据时,为了尽量地址不冲突,会使用多个 hash 函数对 key 进行运算,算得一个下标索引值,然后对位数组长度进行取模运算得到一个位置,每个 hash 函数都会算得一个不同的位置。再把位数组的这几个位置都置为 1 就完成了 add 操作。

3.3.2 查看

向布隆过滤器查询某个key是否存在时,先把这个 key 通过相同的多个 hash 函数进行运算,查看对应的位置是否都为 1,只要有一个位为 0,那么说明布隆过滤器中这个 key 不存在;如果这几个位置全都是 1,那么说明极有可能存在;

3.3.3 优缺点

优点: 高效地插入和查询,占用空间少
缺点: 不能删除元素。因为删掉元素会导致误判率增加,因为hash冲突同一个位置可能存的东西是多个共有的,你删除一个元素的同时可能也把其它的删除了。
存在误判,不同的数据可能出来相同的hash值。

3.4 布隆过滤器的实现

3.4.1 pom

 <!--guava Google 开源的 Guava 中自带的布隆过滤器-->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>23.0</version>
        </dependency>

3.4.2 UT

 public class GuavaBloomFilterTest 


    /**
     *  布隆过滤器预计插入多少数据 100w
     */
    private static final int SIZE = 100 * 10000;

    /**
     * 误判率
     */
    private static final double fpp = 0.01;


    @Test
    public void mainTest() 
        //创建布隆过滤器
        BloomFilter<Integer> filter = BloomFilter.create(Funnels.integerFunnel(), SIZE, fpp);
        //100w 存
        for (int i = 1; i <= SIZE; i++) 
            filter.put(i);
        

        //判断100W的数据是否都在布隆过滤器
        List<Integer> list1 = new ArrayList<>(SIZE);
        for (int i = 1; i <= SIZE; i++) 
            if (filter.mightContain(i)) 
                list1.add(i);
            
        
        System.out.println("存在的数量:" + list1.size());
        //取10W个不在布隆过滤器里面的值,判断误判
        List<Integer> list2 = new ArrayList<>(SIZE);
        for (int i = SIZE + 1; i <= SIZE + 1 + 100000; i++) 
            if (filter.mightContain(i)) 
                list2.add(i);
            
        
        System.out.println("误判的数量:" + list2.size());
    





redis缓存雪崩缓存穿透缓存击穿

...edis缓存雪崩、缓存穿透、缓存击穿Redis缓存过程缓存雪崩解决方案永不过期合理的设置过期时间使用Redis的分布式锁缓存穿透解决方案过滤非法查询缓存空对象布隆过滤器布隆过滤器的新增布隆过滤器的查询布隆过滤器的删除布... 查看详情

redis缓存穿透缓存击穿缓存雪崩的原理和解决办法(代码片段)

Redis缓存穿透、缓存击穿、缓存雪崩的原理和解决办法1.前言2.缓存穿透的解决办法3.缓存击穿解决办法4.缓存雪崩的解决办法1.前言在大数据时代,由于网络请求的并发,导致的数据库I/O开销巨大,所以为了缓解数据库的压力,缓... 查看详情

redis缓存穿透缓存击穿缓存雪崩的原理和解决办法(代码片段)

Redis缓存穿透、缓存击穿、缓存雪崩的原理和解决办法1.前言2.缓存穿透的解决办法3.缓存击穿解决办法4.缓存雪崩的解决办法1.前言在大数据时代,由于网络请求的并发,导致的数据库I/O开销巨大,所以为了缓解数据库的压力,缓... 查看详情

redis的缓存问题之缓存穿透缓存雪崩缓存击穿(代码片段)

目录一、什么是缓存穿透?二、常见的解决方案有两种:1、缓存空对象2、布隆过滤综上所述三、编码解决商品查询的缓存穿透问题四、缓存雪崩问题及解决思路1、什么是缓存雪崩?五、缓存击穿问题及解决思路 1、... 查看详情

redis——缓存穿透缓存击穿缓存雪崩分布式锁(代码片段)

...录:1.缓存穿透1.1什么是缓存穿透?1.2缓存穿透的解决方案2.缓存击穿2.1什么是缓存击穿?2.2缓存击穿的解决方啊3.缓存雪崩3.1什么是缓存雪崩?3.2缓存雪崩的解决方案4.分布式锁4.1使用setnx+del实现分布式锁的添... 查看详情

redis——缓存穿透缓存击穿缓存雪崩分布式锁(代码片段)

...录:1.缓存穿透1.1什么是缓存穿透?1.2缓存穿透的解决方案2.缓存击穿2.1什么是缓存击穿?2.2缓存击穿的解决方啊3.缓存雪崩3.1什么是缓存雪崩?3.2缓存雪崩的解决方案4.分布式锁4.1使用setnx+del实现分布式锁的添... 查看详情

redis12_缓存雪崩缓存穿透基于布隆过滤器解决缓存穿透的问题缓存击穿基于缓存击穿工作实际案例(代码片段)

文章目录①.缓存雪崩②.缓存穿透③.在centos7下布隆过滤器2种安装方式④.缓存击穿⑤.高并发的淘宝聚划算案例落地①.缓存雪崩①.问题的产生:缓存雪崩是指缓存数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至... 查看详情

redis12_缓存雪崩缓存穿透基于布隆过滤器解决缓存穿透的问题缓存击穿基于缓存击穿工作实际案例(代码片段)

文章目录①.缓存雪崩②.缓存穿透③.在centos7下布隆过滤器2种安装方式④.缓存击穿⑤.高并发的淘宝聚划算案例落地①.缓存雪崩①.问题的产生:缓存雪崩是指缓存数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至... 查看详情

redis08_缓存雪崩缓存穿透基于布隆过滤器解决缓存穿透的问题缓存击穿基于缓存击穿工作实际案例(代码片段)

文章目录①.缓存雪崩②.缓存穿透③.在centos7下布隆过滤器2种安装方式④.缓存击穿⑤.高并发的淘宝聚划算案例落地①.缓存雪崩①.问题的产生:缓存雪崩是指缓存数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至... 查看详情

redis缓存穿透击穿雪崩到底是个啥?7张图告诉你(代码片段)

目录一、缓存是什么?二、缓存的作用和成本1、缓存的作用:2、缓存的成本:三、缓存作用模型1、根据id查询数据缓存流程四、缓存更新策略1、内存淘汰2、超时剔除3、主动更新五、缓存穿透解决方法:六、缓... 查看详情

redis之缓存穿透击穿雪崩问题与缓存删除淘汰策略(代码片段)

一、缓存问题与解决缓存穿透缓存穿透是指查询缓存和DB中都不存在的数据。缓存穿透示例:publicStationfindProjectStation(LongstationId)//从缓存中查询Stationstation=(Station)redisTemplate.boundHashOps("project_station").get(stationId);if(station==null)// 查看详情

redis之缓存穿透击穿雪崩问题与缓存删除淘汰策略(代码片段)

一、缓存问题与解决缓存穿透缓存穿透是指查询缓存和DB中都不存在的数据。缓存穿透示例:publicStationfindProjectStation(LongstationId)//从缓存中查询Stationstation=(Station)redisTemplate.boundHashOps("project_station").get(stationId);if(station==null)// 查看详情

redis从入门到进阶第6讲:缓存雪崩击穿穿透场景与解决方案(代码片段)

...对这三个场景我们必须了解其中的差异,以及各自的解决方案。2.缓存雪崩2.1什么是缓存雪崩?  缓存雪崩指的是在同一时间,大量的Key同时失效࿰ 查看详情

redis缓存穿透,缓存击穿,缓存雪崩解决方案以及封装redis工具类(代码片段)

...数据库和redis中都不存在,请求直接打在数据库中。解决方案:方案一:方案二:代码案例实现: //缓存穿透privateShopcacheBreakDown(Longid)//查询redisStringjsonShop=(String)redisTemplate.opsForValue().get(RedisConstants.SHOP_CACHE&#... 查看详情

redis缓存穿透,缓存击穿,缓存雪崩解决方案以及封装redis工具类(代码片段)

...数据库和redis中都不存在,请求直接打在数据库中。解决方案:方案一:方案二:代码案例实现: //缓存穿透privateShopcacheBreakDown(Longid)//查询redisStringjsonShop=(String)redisTemplate.opsForValue().get(RedisConstants.SHOP_CACHE&#... 查看详情

redis缓存穿透,缓存击穿,缓存雪崩解决方案以及封装redis工具类(代码片段)

...数据库和redis中都不存在,请求直接打在数据库中。解决方案:方案一:方案二:代码案例实现: //缓存穿透privateShopcacheBreakDown(Longid)//查询redisStringjsonShop=(String)redisTemplate.opsForValue().get(RedisConstants.SHOP_CACHE&#... 查看详情

如何解决redis缓存雪崩击穿与穿透(代码片段)

Redis最常用使用的场景就是作为业务系统的缓存,既然是作为缓存,那么就不免会碰到缓存常见的问题,即雪崩、击穿与穿透,什么是缓存雪崩、击穿与穿透以及如何解决这几个问题呢?今天我们一起来探讨一... 查看详情

redis缓存击穿(失效)缓存穿透缓存雪崩怎么解决?

...ff0c;QPS=10000左右,读写平均耗时10~100ms。用Redis作为缓存系统正好可以弥补DB的不足,「码哥」在自己的MacBookPro2019上执 查看详情