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
相关推荐
是程序喵呀6 分钟前
Redis实现持久化
数据库·redis·缓存
余槐i24 分钟前
PostgreSQL 加索引后查询反而更慢:优化器弃用索引的 3 种情形
spring boot·redis·mysql·postgresql·事务
我不会起名字32226 分钟前
Redis 从 0 到 1(十三):分布式锁被误删、锁不住?Go 无 Lua 实现 3 级防御
redis·go·分布式锁·watch·setnx
z06.34 分钟前
MySQL存储引擎
数据库·mysql
小徐不徐说35 分钟前
数据库存储基础:理解表结构、主键、事务与 BLOB
开发语言·数据库·c++·qt·程序设计
JackLam39 分钟前
Gitea HTTPS 反向代理配置
数据库
量子物理学41 分钟前
oracle plsql instantclient 安装
数据库·oracle
草莓熊Lotso1 小时前
【C++ 基于微服务的即时通讯系统】网关基建:cpp-httplib 与 WebSocketpp 从入门到实战
linux·开发语言·数据库·c++·redis·微服务·云原生
ClickHouseDB9 小时前
ClickHouse Cloud 与 Snowflake 实时性价比对比:CostBench 测试中的 412 倍差距来
运维·数据库·系统架构
m0_639906949 小时前
Redis入门|五种数据结构、使用场景、持久化RDB&AOF
数据结构·数据库·redis