redis缓存击穿如何解决

是指缓存中没有数据但数据库中有数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,导致短时间内数据库压力剧增,导致崩溃。

缓存击穿的解决方案:

1.设置热点数据永远不过期(热点数据key快要过期时,后台异步线程重新设置缓存)

2.设置互斥锁。在并发的多个请求中,只有第一个请求线程能拿到锁并执行数据库查询操作,其他的线程拿不到锁就阻塞等着,等到第一个线程将数据写入缓存后,直接走缓存。

//        ----------------
        {
            String lockId = UUID.randomUUID().toString();
            //循环抢锁
            while (Boolean.FALSE.equals(stringRedisTemplate.opsForValue().setIfAbsent("lock1020", lockId, 30, TimeUnit.SECONDS))
            ) {
                try {
                    Thread.sleep(50L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //拿到这把锁,
            //value  商品库存800

            try {
                String testLock10 = stringRedisTemplate.opsForValue().get("testLock10");
                int i = Integer.parseInt(testLock10);
                i--;//商品库存-1
                stringRedisTemplate.opsForValue().set("testLock10", String.valueOf(i));
            } finally {
                String lockIdInRedis = stringRedisTemplate.opsForValue().get("lock1020");
                if (lockId.equals(lockIdInRedis)) {
                    //此锁是我加的,释放锁this lock is set by me,unlock it;
                    stringRedisTemplate.delete("lock1020");
                }
            }
        }
//                 -------------------------

(可以使用 Redis 分布式锁)

(1) 就是在缓存失效的时候(判断拿出来的值为空),不是立即去加载数据库。

(2) 先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX,java对应redisTemplate.setIfAbsent("

))去set一个互斥锁。

(3) 当操作返回成功时,再进行加载数据库的操作,并回设缓存,最后删除mutex key(互斥锁);

(4) 当操作返回失败,证明有线程在加载数据库,当前线程睡眠一段时间再重试整个get缓存的方法。

3.接口限流与熔断,降级。重要的接口一定要做好限流策略,防止用户恶意刷接口,同时要做好降级准备,当接口中的某些服务不可用时候,进行熔断,建立失败快速返回机制。(可以借助sentinel,gateway等处理熔断降级)

经验分享 程序员 微信小程序 职场和发展