• redis——缓存雪崩、缓存穿透、缓存击穿


    通常我们为了保证缓存中的数据与数据库中的数据一致性,会给 Redis 里的数据设置过期时间,当缓存数据过期后,用户访问的数据如果不在缓存里,业务系统需要重新生成缓存,因此就会访问数据库,并将数据更新到 Redis 里,这样后续请求都可以直接命中缓存。

    缓存雪崩

    如果同一时间大量的缓存数据同时过期(失效)或redis服务宕机,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机。
    在这里插入图片描述发生缓存雪崩有两个原因

    • 大量的缓存数据同时过期(失效)
    • redis服务宕机

    大量的缓存数据同时过期(失效)的解决方案

    1、随机设置过期时间 (TTL)
    2、互斥锁

    当业务线程在处理用户请求时,如果发现访问的数据不在 Redis 里,就加个互斥锁,保证同一时间内只有一个请求来构建缓存(从数据库读取数据,再将数据更新到 Redis 里),当缓存构建完成后,再释放锁。未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。

    实现互斥锁的时候,最好设置超时时间,不然第一个请求拿到了锁,然后这个请求发生了某种意外而一直阻塞,一直不释放锁,这时其他请求也一直拿不到锁,整个系统就会出现无响应的现象。

    3、双 key 策略

    我们对缓存数据可以使用两个 key,一个是主 key,会设置过期时间,一个是备 key,不会设置过期,它们只是 key 不一样,但是 value 值是一样的,相当于给缓存数据做了个副本。

    当业务线程访问不到「主 key 」的缓存数据时,就直接返回「备 key 」的缓存数据,然后在更新缓存的时候,同时更新「主 key 」和「备 key 」的数据。

    4、多级缓存

    jvm本地缓存,nginx缓存等

    Redis 故障宕机引发的缓存雪崩的解决方案

    服务熔断或请求限流机制 (sentinel);
    构建 Redis 缓存高可用集群 (主从集群);

    缓存击穿

    缓存击穿也称(热点key问题),一个被高并发访问缓存业务重建困难的key突然过期(失效)了,于是全部请求都直接访问数据库,从而导致数据库的压力骤增甚至宕机。
    如:tb秒杀活动,wb热榜等

    在这里插入图片描述

    解决方案

    1、互斥锁

    在这里插入图片描述
    互斥锁保证同一时间只有一个业务线程更新缓存,未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。最后给锁也添加过期时间

    redis命令

    SETNX KEY_NAME VALUE
    
    • 1

    使用setIfAbsent,boot2.1版本以上才支持

    stringRedisTemplate.opsForValue().setIfAbsent(key, "1",10, TimeUnit.SECONDS);
    
    • 1

    使用lua脚本

    private Boolean tryGetLock1(String key){
    
            /** redisUtil.setIfAbsent 新加的带有超时的setIfAbsent 脚本*/
            //KEYS[1] 用来表示在redis 中用作键值的参数占位,
            // 主要用來传递在redis 中用作keys值的参数
    
            // ARGV[1] 用来表示在redis 中用作参数的占位,
            // 主要用来传递在redis中用做 value值的参数。
            String newSetIfAbsentScriptStr = " if 1 == redis.call('setnx',KEYS[1],ARGV[1]) then" +
                    " return 1;" +
                    " else" +
                    " return 0;" +
                    " end;";
            //创建 redis脚本对象
            RedisScript<Boolean> newSetIfAbsentScript = new DefaultRedisScript<>(newSetIfAbsentScriptStr,Boolean.class);
            List<String> keys = new ArrayList<>();
            keys.add(key);  // key
            Object[] values = {"1"};  // value
            // 执行脚本
            Boolean res = stringRedisTemplate.execute(newSetIfAbsentScript, keys, values);
            System.out.println("result:"+res);
            return res;
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    2、逻辑过期

    在这里插入图片描述
    逻辑过期是指不给热点数据设置过期时间,由后台异步更新缓存,或者在热点数据准备要过期前,提前通知后台线程更新缓存以及重新设置过期时间

    互斥锁和逻辑过期对比
    在这里插入图片描述

    缓存穿透

    缓存穿透是指客户端请求的数据在缓存和数据库中都不存在,于是全部请求都直接访问数据库,从而导致数据库的压力骤增甚至宕机。
    在这里插入图片描述
    存在原因:恶意攻击,故意大量访问某些读取不存在数据的业务

    解决方案

    1、请求校验

    2、缓存空对象

    3、布隆过滤器

    布隆过滤器校验的结果特点是:

    • 若过滤器判断某个元素存在,那么这个元素不一定存在
    • 若过滤器判断某个元素不存在,那么这个元素一定不存在
      布隆过滤器讲解:https://blog.csdn.net/cssweb_sh/article/details/124284785
  • 相关阅读:
    Nacos注册中心配置安装和问题解决
    Java项目:SSM汽车维修中心管理系统
    Linux系统运行时参数命令
    Docker容器化技术(从零学会Docker)
    基于XML配置的AOP
    用函数的方法通过冒泡法实现对一个数组(乱序)到有序排序(由大到小排序)
    centos8 Error: Failed to download metadata for repo ‘appstream‘
    Web的三大作用域详解
    win11恢复win10形式的右键显示
    Eclipse常用设置
  • 原文地址:https://blog.csdn.net/m0_46267375/article/details/125941637