缓存击穿、雪崩、穿透

缓存击穿

    /**
     * 缓存击穿:高并发时,当一个key非常热点(热销品),在不停的扛着大并发,当这个key在失效的瞬间,持续的大并发就击穿缓存,直接请求数据库后再缓存数据,导致性能下降
     * 解决方案:永不过期 或 加锁排队 或 两者都有
     *
     * @param key 键
     * @return {@link String}
     */
    public String cacheBreakdown(String key) {
        String value = stringRedisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(value)) {
            return value;
        }
        synchronized (this) {
            value = stringRedisTemplate.opsForValue().get(key);
            if (StringUtils.isNotBlank(value)) {
                return value;
            }
            // 从数据库中获取数据
            value = selectDb(key);
            stringRedisTemplate.opsForValue().set(key, value, Duration.ofHours(1L));
        }
        return value;
    }

缓存雪崩

    /**
     * 缓存雪崩:缓存集中过期,或者缓存服务器宕机,导致大量请求访问数据库,造成数据库瞬间压力过大,宕机
     * 解决方案:加锁排队 和 随机失效时间 和 redis集群部署
     *
     * @param key 钥匙
     * @return {@link String}
     */
    public String cacheAvalanche(String key) {
        String value = stringRedisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(value)) {
            return value;
        }
        synchronized (this) {
            value = stringRedisTemplate.opsForValue().get(key);
            if (StringUtils.isNotBlank(value)) {
                return value;
            }
            // 从数据库中获取数据
            value = selectDb(key);
            // 设置随机失效时间
            long hour = ThreadLocalRandom.current().nextLong(1L, 31L);
            stringRedisTemplate.opsForValue().set(key, value, Duration.ofHours(hour));
        }
        return value;
    }

缓存穿透

    /**
     * 缓存穿透:数据库不存在且缓存中也不存在,导致每次请求都会查询数据库,这时的请求很可能是攻击者,伪造不存在的 key ,导致数据库压力过大或宕机
     * 解决方案:参数校验(如ID≤0的key值请求一律返回空) 和 缓存空对象 和 使用 bloom 过滤器
     *
     * @param key 钥匙
     * @return {@link String}
     */
    public String cachePenetration(String key) {
        // RedissonClient redissonClient = Redisson.create();
        RBloomFilter bloomFilter = redissonClient.getBloomFilter("bloom:filter:data");
        if (!bloomFilter.contains(Long.parseLong(key))) {
            return null;
        }
        String value = stringRedisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(value)) {
            return value;
        }
        synchronized (this) {
            value = stringRedisTemplate.opsForValue().get(key);
            if (StringUtils.isNotBlank(value)) {
                return value;
            }
            // 从数据库中获取数据
            value = selectDb(key);
            if (StringUtils.isBlank(value)) {
                // 缓存空对象
                stringRedisTemplate.opsForValue().set(key, "{}", Duration.ofMinutes(10L));
                return value;
            }
            // 设置随机失效时间
            long hour = ThreadLocalRandom.current().nextLong(1L, 31L);
            stringRedisTemplate.opsForValue().set(key, value, Duration.ofHours(hour));
        }
        return value;
    }

你可能感兴趣的:(Java,Redis,缓存,redis,Redisson)