Redis的缓存击穿,缓存雪崩,缓存穿透问题

Redis的缓存击穿,缓存雪崩,缓存穿透问题

引言

在分布式系统中,缓存是一种常用的提升性能和减轻数据库压力的手段。然而,缓存系统也存在一些常见的问题,如缓存击穿、缓存雪崩和缓存穿透。这些问题如果不加以解决,可能会导致系统性能下降,甚至崩溃。本文将详细介绍这三个问题是如何发生的,并说明在Spring开发框架中的解决方案。

缓存击穿

问题描述

缓存击穿(Cache Breakdown)指的是缓存中某个热点数据在失效的瞬间,有大量请求同时到达该缓存节点,从而导致请求直接打到数据库上,造成数据库瞬时压力过大。

发生原因

当某一热点数据在缓存中过期,而此时有大量请求并发访问该数据时,由于缓存失效,所有请求都会直接访问数据库,造成数据库的瞬时高并发压力。

解决方案

在Spring中,可以使用以下方法来解决缓存击穿问题:

  1. 使用互斥锁:在缓存失效时,使用互斥锁(如Redis分布式锁)控制只有一个线程能够访问数据库,其它线程等待,从而避免数据库被击穿。
java 复制代码
String cacheKey = "hotData";
String data = redisTemplate.opsForValue().get(cacheKey);
if (data == null) {
    synchronized (this) {
        data = redisTemplate.opsForValue().get(cacheKey);
        if (data == null) {
            data = databaseService.getDataFromDb();
            redisTemplate.opsForValue().set(cacheKey, data, 1, TimeUnit.HOURS);
        }
    }
}
return data;
  1. 提前预热缓存:在热点数据过期前,通过后台任务或者定时任务提前刷新缓存,保证热点数据始终在缓存中存在。
java 复制代码
@Scheduled(fixedRate = 3600000)
public void preloadCache() {
    String hotData = databaseService.getHotDataFromDb();
    redisTemplate.opsForValue().set("hotData", hotData, 1, TimeUnit.HOURS);
}

缓存雪崩

问题描述

缓存雪崩(Cache Avalanche)指的是在某一时刻,缓存中大量数据同时失效,大量请求直接打到数据库,造成数据库压力剧增甚至宕机。

发生原因

缓存雪崩通常发生在缓存集群中某些节点同时失效,或者缓存设置了相同的过期时间导致大量数据同时过期。

解决方案

在Spring中,可以采用以下策略解决缓存雪崩问题:

  1. 设置不同的缓存失效时间:为不同的缓存数据设置不同的过期时间,避免大量缓存数据同时失效。
java 复制代码
redisTemplate.opsForValue().set("data1", data1, randomExpireTime(), TimeUnit.SECONDS);
redisTemplate.opsForValue().set("data2", data2, randomExpireTime(), TimeUnit.SECONDS);

private long randomExpireTime() {
    return 3600 + new Random().nextInt(600);
}
  1. 使用二级缓存:通过引入本地缓存(如Guava Cache)和远程缓存(如Redis),形成多级缓存架构,减轻缓存失效时对数据库的直接压力。
java 复制代码
Cache<String, String> localCache = CacheBuilder.newBuilder()
        .expireAfterWrite(10, TimeUnit.MINUTES)
        .maximumSize(1000)
        .build();

public String getData(String key) {
    String data = localCache.getIfPresent(key);
    if (data == null) {
        data = redisTemplate.opsForValue().get(key);
        if (data == null) {
            data = databaseService.getDataFromDb();
            redisTemplate.opsForValue().set(key, data, 1, TimeUnit.HOURS);
        }
        localCache.put(key, data);
    }
    return data;
}

缓存穿透

问题描述

缓存穿透(Cache Penetration)指的是查询一个不存在的数据时,因为缓存中没有该数据的记录,请求直接到达数据库,并且数据库也没有该数据,导致每次请求都穿透缓存直接查询数据库。

发生原因

缓存穿透通常是由于恶意请求或者错误请求频繁查询缓存中不存在的数据,缓存未能对此类请求进行有效处理。

解决方案

在Spring中,可以通过以下方法解决缓存穿透问题:

  1. 缓存空值:对于查询结果为空的数据也进行缓存,设置一个较短的过期时间,防止相同请求频繁穿透缓存。
java 复制代码
String data = redisTemplate.opsForValue().get(cacheKey);
if (data == null) {
    data = databaseService.getDataFromDb();
    if (data == null) {
        redisTemplate.opsForValue().set(cacheKey, "", 5, TimeUnit.MINUTES);
    } else {
        redisTemplate.opsForValue().set(cacheKey, data, 1, TimeUnit.HOURS);
    }
}
return data; 
  1. 使用布隆过滤器:在缓存前增加布隆过滤器,用于快速判断请求的数据是否存在,避免对不存在的数据频繁查询数据库。
java 复制代码
@Bean
public BloomFilter<String> bloomFilter() {
    return BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), 10000);
}

@Autowired
private BloomFilter<String> bloomFilter;

public String getData(String key) {
    if (!bloomFilter.mightContain(key)) {
        return null;
    }
    String data = redisTemplate.opsForValue().get(key);
    if (data == null) {
        data = databaseService.getDataFromDb();
        if (data != null) {
            redisTemplate.opsForValue().set(key, data, 1, TimeUnit.HOURS);
            bloomFilter.put(key);
        }
    }
    return data;
}

参考链接

  1. Redis 官方文档
  2. Spring Cache 官方文档
  3. Guava Cache 官方文档
  4. 布隆过滤器 Wikipedia
相关推荐
消失的旧时光-194315 分钟前
第十四课:Redis 在后端到底扮演什么角色?——缓存模型全景图
java·redis·缓存
devmoon35 分钟前
在 Polkadot Runtime 中添加多个 Pallet 实例实战指南
java·开发语言·数据库·web3·区块链·波卡
认真的薛薛1 小时前
数据库-sql语句
数据库·sql·oracle
爱学英语的程序员1 小时前
面试官:你了解过哪些数据库?
java·数据库·spring boot·sql·mysql·mybatis
消失的旧时光-19432 小时前
第十四课 · 实战篇:Redis 缓存系统落地指南(Spring Boot 从 0 到可用)
spring boot·redis·缓存
·云扬·2 小时前
MySQL Redo Log落盘机制深度解析
数据库·mysql
用户982863025682 小时前
pg内核实现细节
数据库
飞升不如收破烂~2 小时前
Redis 分布式锁+接口幂等性使用+当下流行的限流方案「落地实操」+用户连续点击两下按钮的解决方案自用总结
数据库·redis·分布式
森焱森2 小时前
详解 Spring Boot、Flask、Nginx、Redis、MySQL 的关系与协作
spring boot·redis·python·nginx·flask
workflower2 小时前
业务需求-假设场景
java·数据库·测试用例·集成测试·需求分析·模块测试·软件需求