Redis:缓存击穿,缓存穿透,缓存雪崩

缓存穿透

缓存和数据库中都没有的数据,可用户还是源源不断的发起请求,导致每次请求都会到数据库,从而压垮数据库。

这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。

*** 解决方案**

  • 对空值进行缓存标志
    • 对于不存在的数据,同样设置一个特殊的 Value 到缓存中,并设置过期时间
  • 使用布隆过滤器
    • 如果布隆过滤器认为值不存在,那么值一定是不存在的,无需查询缓存也无需查询数据库;
    • 对于极小概率的误判请求,才会最终让非法 Key 的请求走到缓存或数据库。
  • 业务层校验
    • 用户发过来的请求,根据请求参数进行校验,对于明显错误的参数,直接拦截返回。

缓存雪崩

​ 缓存雪崩是指当缓存中有大量的key在同一时刻过期,或者Redis直接宕机了,导致大量的查询请求全部到达数据库,造成数据库查询压力骤增,甚至直接挂掉。

​ 和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。

*** 现象 ** :数据库的访问压力瞬间激增,服务负载过高

产生雪崩的原因大致有两种

  • 缓存系统不可用
  • 大量的key在同一时间失效,导致大量数据回源

解决方案

  • 1、差异化缓存过期时间

    • 避免缓存设置相近的有效期,我们可以在设置有效期时增加随机值;
  • 2、缓存永不过期,后台线程刷新

    • 初始化缓存数据的时候设置缓存永不过期,然后启动一个后台线程 30 秒一次定时把所有数据更新到缓存,而且通过适当的休眠,控制从数据库更新数据的频率,降低数据库压力
  • 3、增强redis的高可用性

    • 构建 Redis 缓存高可靠集群

缓存击穿

在某些 Key 属于极端热点数据,且并发量很大的情况下,如果这个 Key 过期,可能会在某个瞬间出现大量的并发请求同时回源,相当于大量的并发请求直接打到了数据库。这种情况,就是我们常说的缓存击穿或缓存并发问题。

*** 现象 ** :数据库的访问压力瞬间激增,Redis正常运行

*** 解决办法**

  • 业务允许下,设置缓存永不过期

    • 启动一个后台线程 30 秒一次定时把所有数据更新到缓存,而且通过适当的休眠,控制从数据库更新数据的频率,降低数据库压力
  • 使用互斥锁

    • 缓存失效的时候(判断拿出来的值为空),不是立即去加载数据库。
    • 先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX)去set一个mutex key。
    • 当操作返回成功时,再进行加载数据库的操作,并回设缓存,最后删除mutex key。
    • 当操作返回失败,证明有线程在加载数据库,当前线程睡眠一段时间再重试整个get缓存的方法。

@Autowired
    private RedissonClient redissonClient;
    @GetMapping("mutex")
    public String mutex() {
        String data = stringRedisTemplate.opsForValue().get("hot_key");
        if (StringUtils.isEmpty(data)) {
            RLock locker = redissonClient.getLock("mutex_locker");
            //获取分布式锁
            if (locker.tryLock()) {
                try {
                    data = stringRedisTemplate.opsForValue().get("hot_key");
                    //双重检查,因为可能已经有一个B线程过了第一次判断,在等锁,然后A线程已经把数据写入了Redis中
                    if (StringUtils.isEmpty(data)) {
                        //回源到数据库查询
                        data = getDatabaseData();
                        stringRedisTemplate.opsForValue().set("hot_key", data, 5, TimeUnit.SECONDS);
                    }
                } finally {
                    //别忘记释放,另外注意写法,获取锁后整段代码try+finally,确保unlock万无一失
                    locker.unlock();
                }
            }
        }
        return data;
    }

缓存穿透和缓存击穿的区别:

  • 缓存穿透是指,缓存没有起到压力缓冲的作用;
  • 而缓存击穿是指,缓存失效时瞬时的并发打到数据库。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半山猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值