欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 手游 > 【Redis进阶】缓存应用

【Redis进阶】缓存应用

2025/4/27 6:58:21 来源:https://blog.csdn.net/2401_83045332/article/details/140999930  浏览:    关键词:【Redis进阶】缓存应用

目录

缓存击穿

概念

缓存击穿的原因

缓存击穿的影响

缓存击穿的应对措施

设置分布式锁

提前更新缓存

请求分级和降级

缓存穿透

概念

缓存穿透的原因

缓存穿透的应对措施

缓存空值

布隆过滤器

 限流和黑名单

缓存雪崩

缓存雪崩概念

缓存雪崩的原因

应对措施

缓存过期时间随机化:

多级缓存架构

限流

预热缓存


缓存击穿

概念

缓存击穿是指缓存中不存在但数据库中存在的数据请求,由于缓存没有命中,导致请求直接落到数据库上,造成数据库压力骤增。缓存击穿常常发生在某些热点数据上,比如某个高访问频率的热点键突然失效时,大量请求直接穿透缓存访问数据库。

缓存击穿的原因

热点数据缓存失效:高访问频率的热点数据在缓存中失效,导致大量请求直接访问数据库。

缓存设置不当:如缓存策略不合理,过期时间设置过短等

突发流量:突发性的大量请求几种访问某个热点数据,导致缓存来不及重建,直接击穿到数据库。

缓存击穿的影响

数据库压力骤增:大量请求直接访问数据库,可能导致数据库负载过高甚至崩溃。

响应延迟增加:缓存击穿会导致请求需要经过数据库查询,响应时间变长,影响用户体验。

系统稳定性降低:数据库过载可能引发系统不稳定,甚至导致服务不可用。

缓存击穿的应对措施

设置分布式锁

在缓存失效时,通过加锁机制,确保只有一个线程去加载数据并更新缓存,其他线程等待锁释放后再读取缓存。

提前更新缓存

在缓存失效前主动更新缓存。可以使用定时任务或异步任务,在缓存即将过期时提前刷新缓存。

请求分级和降级

  • 针对缓存击穿的情况,可以对请求进行分级处理,优先保证核心请求。
  • 对非核心请求进行降级处理,如返回默认值或错误提示。

缓存穿透

概念

缓存穿透是指请求的数据既不在缓存中,也不存在于数据库中,导致每次请求都直接达到数据库。由于这些请求无法通过缓存过滤掉,所有的请求都到达数据库。可能会对数据库造成巨大压力。

缓存穿透的原因

恶意攻击:攻击者故意构造大量不存在的key进行请求,绕过缓存,直接打到数据库,造成数据库压力骤增。

业务设计缺陷:正常业务逻辑中,存在大量的不存在的数据请求,未合理处理,导致频繁穿透缓存。

用户错误输入:用户输入错误或者不规范的数据,导致请求的数据在缓存和数据库中都不存在。

缓存穿透的应对措施

缓存空值

  • 对于查询结果为空的数据,也将其缓存起来,避免下一次请求再次穿透过数据库。
String key = "nonExistingKey";
String value = redis.get(key);if (value == null) {value = db.get(key);if (value == null) {// 将空值写入缓存,并设置合理的过期时间redis.set(key, "", 60); // 60秒过期} else {redis.set(key, value, 300); // 300秒过期}
}

布隆过滤器

  • 使用布隆过滤器在缓存前进行一次快速判断,如果布隆过滤器判断该 key 不存在,则直接返回,不再查询缓存和数据库。
// 初始化布隆过滤器
BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), expectedInsertions);// 添加存在的key到布隆过滤器
bloomFilter.put("existingKey1");
bloomFilter.put("existingKey2");String key = "nonExistingKey";
if (!bloomFilter.mightContain(key)) {return null; // 直接返回,不查询缓存和数据库
}// 正常的缓存和数据库查询流程
String value = redis.get(key);
if (value == null) {value = db.get(key);redis.set(key, value);
}

 限流和黑名单

  • 对于明显的恶意请求,可以采取限流和黑名单策略,限制其访问频率或直接拒绝其请求。
String clientIp = getClientIp();
if (isBlacklisted(clientIp)) {return null; // 直接返回,不查询缓存和数据库
}// 正常的缓存和数据库查询流程
String key = "someKey";
String value = redis.get(key);
if (value == null) {value = db.get(key);redis.set(key, value);
}

缓存雪崩

缓存雪崩概念

缓存雪崩是指由于大量缓存数据在同一时间过期或失效,导致后续的所有请求都直接访问数据库,瞬间增加数据库的负载。与缓存击穿不同,缓存雪崩通常影响的是大批量的缓存数据,而不是单个热点数据。

缓存雪崩的原因

  • 缓存过期时间设置不合理:大批量缓存键设定了相同或相近的过期时间,导致它们在同一时间点失效。
  • 突发流量:在流量高峰期,如果缓存失效,短时间内会有大量请求同时涌入数据库。
  • 缓存服务宕机:缓存服务(如 Redis 实例)出现宕机或重启,导致所有缓存失效,所有请求直接击中数据库。

应对措施

缓存过期时间随机化:

  • 在设置缓存过期时间时,添加一定的随机时间,使得不同的缓存键有不同的过期时间,避免大量缓存键在同一时间失效。
// 伪代码示例
int baseExpireTime = 600; // 基础过期时间600秒
int randomTime = new Random().nextInt(300); // 随机附加300秒
int expireTime = baseExpireTime + randomTime;
redis.set(key, value, expireTime);

多级缓存架构

  • 通过引入本地缓存(如 Guava Cache)和分布式缓存(如 Redis)相结合的多级缓存架构,减少直接访问数据库的请求数量。
// 伪代码示例
String key = "someKey";
String value = localCache.get(key);if (value == null) {value = redis.get(key);if (value == null) {value = db.get(key);redis.set(key, value);}localCache.put(key, value);
}

限流

  • 通过限流机制控制高并发请求的流量,防止因大量请求同时访问数据库而导致数据库崩溃。
// 伪代码示例
if (!rateLimiter.tryAcquire()) {return "Service is busy, please try again later.";
}String key = "someKey";
String value = redis.get(key);if (value == null) {value = db.get(key);redis.set(key, value);
}return value;

预热缓存

  • 在高峰期来临之前,预先将热点数据加载到缓存中,避免在流量高峰期缓存失效导致的雪崩。
// 伪代码示例
@Scheduled(fixedRate = 60000) // 每分钟执行一次
public void preheatCache() {String key = "hotKey";String value = db.get(key);redis.set(key, value);
}

希望本文能帮助大家更好地理解和应对 Redis 缓存击穿,缓存穿透,缓存雪崩问题。

版权声明:

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

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

热搜词