欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > Redis的缓存雪崩和缓存穿透的理解和如何避免

Redis的缓存雪崩和缓存穿透的理解和如何避免

2025/4/2 10:46:00 来源:https://blog.csdn.net/hekai7217/article/details/146590860  浏览:    关键词:Redis的缓存雪崩和缓存穿透的理解和如何避免

Redis中的缓存雪崩与缓存穿透

缓存雪崩缓存穿透 是两个常见的缓存问题,它们会直接影响系统性能,尤其是在高并发的场景下。


1. 缓存雪崩(Cache Avalanche)

定义:缓存雪崩是指大量缓存数据在同一时刻失效,导致大量请求直接访问数据库,造成数据库的压力剧增,可能导致系统崩溃或响应时间大幅延迟。

原因

  • 如果缓存数据的过期时间设置相同,所有缓存数据可能会在同一时刻失效,导致大量的请求同时穿透缓存访问数据库,给数据库带来极大压力。

解决方案

  1. 设置不同的缓存过期时间:避免所有数据在同一时刻过期,可以通过设置缓存的过期时间随机化来减少过期数据集中失效的风险。
  2. 使用互斥锁(Mutex):防止多个请求在缓存失效时同时访问数据库。可以通过互斥锁机制确保只有一个请求访问数据库,其他请求可以等待缓存的重新加载。
  3. 预热缓存:在系统启动时或数据库数据变动时,提前加载缓存,避免缓存为空导致大量请求直接访问数据库。

2. 缓存穿透(Cache Penetration)

定义:缓存穿透是指查询的缓存数据和数据库中都不存在的数据,导致每次查询都需要访问数据库,从而造成数据库负载增加。

原因

  • 请求查询的数据不在缓存中,也不在数据库中,导致每次都需要访问数据库。

解决方案

  1. 缓存空值:当查询结果为空时,将空值缓存一段时间,避免后续请求直接穿透缓存访问数据库。
  2. 请求参数校验:对请求参数进行校验,防止恶意请求访问不存在的数据。
  3. 布隆过滤器:通过布隆过滤器提前拦截不存在的数据请求,避免对不存在的数据访问数据库。

3. Java中使用RedisTemplate的代码示例

在Spring中,RedisTemplate 是一个非常常用的工具,它能够方便地与Redis进行交互。下面我们会给出 缓存雪崩缓存穿透 的相关解决方案代码。

1. 缓存雪崩的解决方案
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;@Service
public class CacheAvalancheService {@Autowiredprivate RedisTemplate<String, String> redisTemplate;public String getData(String key) {// 1. 检查缓存String cachedData = redisTemplate.opsForValue().get(key);if (cachedData == null) {  // 缓存未命中synchronized (CacheAvalancheService.class) {cachedData = redisTemplate.opsForValue().get(key); // 二次检查缓存if (cachedData == null) {// 2. 查询数据库cachedData = getDataFromDatabase(key);// 3. 设置随机过期时间,避免缓存雪崩long expiration = 5 + (long)(Math.random() * 5); // 过期时间5~10秒redisTemplate.opsForValue().set(key, cachedData, expiration, TimeUnit.SECONDS);}}}return cachedData;}private String getDataFromDatabase(String key) {// 模拟从数据库获取数据return "data-from-db"; // 实际中可以是数据库查询操作}
}
解决方案说明:
  • 缓存失效时,加锁:通过 synchronized 确保只有一个线程可以访问数据库,其他线程等待。
  • 设置随机过期时间:通过 Math.random() 设置不同的过期时间,避免大量缓存数据同时失效。

2. 缓存穿透的解决方案
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;@Service
public class CachePenetrationService {@Autowiredprivate RedisTemplate<String, String> redisTemplate;public String getData(String key) {// 1. 检查缓存String cachedData = redisTemplate.opsForValue().get(key);if (cachedData == null) {  // 如果缓存中没有数据// 2. 查询数据库String dataFromDb = getDataFromDatabase(key);if (dataFromDb == null) {  // 如果数据库中也没有数据// 3. 缓存空值redisTemplate.opsForValue().set(key, "", 60, TimeUnit.SECONDS); // 空值缓存,避免频繁查询return null; // 返回空值} else {// 4. 将数据库数据缓存起来redisTemplate.opsForValue().set(key, dataFromDb, 60, TimeUnit.SECONDS); // 设置有效数据缓存return dataFromDb;}}return cachedData;  // 缓存命中}private String getDataFromDatabase(String key) {// 模拟数据库查询return null; // 假设数据库查询不到数据}
}
解决方案说明:
  • 缓存空值:当数据库查询到空数据时,将空值(如 """null")缓存一段时间,避免相同请求频繁查询数据库。
  • 数据库查询:如果缓存没有数据,直接查询数据库并将结果缓存。如果数据库查询不到数据,则缓存空值。

4. 总结与优化

  1. 缓存雪崩
    • 解决方案:设置不同的缓存过期时间、使用互斥锁保证只有一个请求查询数据库、预热缓存。
    • 效果:避免大量缓存同时失效导致的数据库压力。
  2. 缓存穿透
    • 解决方案:缓存空值、参数校验、布隆过滤器。
    • 效果:避免频繁查询数据库的无效请求,减少数据库负担。

通过这些策略,可以有效地避免缓存雪崩和缓存穿透问题,提升系统的性能和稳定性。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词