70人参与 • 2026-05-07 • Redis
在现代高并发的分布式系统架构中,
redis凭借其高性能的内存读写能力,已成为企业级应用不可或缺的缓存中间件。然而,缓存的引入虽然极大地提升了系统响应速度,降低了数据库负载,但也带来了一系列复杂的边缘风险。
1. 定义与问题
缓存穿透是指查询一个数据库根本不存在的数据。由于缓存中无对应key,请求直接穿透缓存层访问数据库。若大量此类请求存在(如恶意攻击或业务误操作),数据库将承受巨大压力,甚至崩溃。
2. 核心原因
3. 解决方案
(1)缓存空值
public object getdata(string key) {
object value = redis.get(key);
if (value == null) { // 缓存未命中
value = db.querydata(key); // 查询数据库
if (value == null) { // 数据不存在
redis.set(key, "null", 60); // 缓存空值,过期时间1分钟
} else {
redis.set(key, value, 3600); // 缓存有效数据,过期时间1小时
}
}
return value;
}(2)布隆过滤器(bloom filter)[推荐]
bloomfilter<string> filter = bloomfilter.create(funnels.stringfunnel(), 1000000, 0.01); // 容量100万,误判率1%
// 初始化:将数据库所有key预加载到布隆过滤器
filter.putall(db.getallkeys());
public object getdata(string key) {
if (!filter.mightcontain(key)) { // 布隆过滤器判断不存在
return null; // 直接返回,不访问数据库
}
object value = redis.get(key);
if (value == null) {
value = db.querydata(key);
redis.set(key, value, 3600);
}
return value;
}1. 定义与问题
缓存击穿又称热点key问题,指一个访问极其频繁的热点key突然失效,大量并发请求同时穿透缓存,直接冲击数据库。例如,电商平台秒杀商品的缓存过期瞬间,大量用户抢购导致数据库崩溃。
2. 核心原因
3. 解决方案
(1)互斥锁(分布式锁)[推荐]
public object getdata(string key) {
object value = redis.get(key);
if (value == null) { // 缓存未命中
if (redis.setnx(key + "_lock", "1", 10)) { // 获取锁,过期时间10秒
try {
value = db.querydata(key); // 查询数据库
redis.set(key, value, 3600); // 重建缓存
} finally {
redis.del(key + "_lock"); // 释放锁
}
} else { // 未获取锁,等待重试
thread.sleep(50);
return getdata(key); // 递归调用
}
}
return value;
}(2)逻辑过期(不设置物理过期)
public class cachedata {
private object data;
private long expiretime; // 逻辑过期时间戳
}
public object getdata(string key) {
cachedata data = redis.get(key);
if (data == null) {
data = db.querydata(key);
redis.set(key, data, 3600);
}
if (data.expiretime < system.currenttimemillis()) { // 逻辑过期
thread asyncthread = new thread(() -> {
// 异步更新缓存
cachedata newdata = db.querydata(key);
redis.set(key, newdata, 3600);
});
asyncthread.start();
}
return data.data;
}1. 定义与问题
缓存雪崩指大量缓存key同时过期或redis服务宕机,导致所有请求穿透缓存,直接压垮数据库,引发系统瘫痪。例如,电商平台商品缓存统一过期,凌晨用户访问高峰导致mysql崩溃。
2. 核心原因
3. 解决方案(分层防御)
(1)过期时间错开
redis.set(key, value, 3600 + new random().nextint(300)); // 基础1小时 + 0-5分钟随机
(2)redis高可用集群
(3)本地缓存兜底
loadingcache<string, object> localcache = caffeine.newbuilder()
.expireafterwrite(30, timeunit.minutes) // 本地缓存过期30分钟
.build(key -> redis.get(key));
public object getdata(string key) {
object value = localcache.get(key);
if (value == null) {
value = redis.get(key);
localcache.put(key, value);
}
return value;
}(4)缓存预热
public void warmupcache() {
list<string> hotkeys = db.gettopnkeys(); // 获取top n热点key
for (string key : hotkeys) {
redis.set(key, db.querydata(key), 3600);
}
}通过以上方案组合使用,可大幅提升系统稳定性,避免因缓存问题导致的服务崩溃。架构设计时需根据实际业务场景权衡性能与一致性,选择最适合的解决方案。
到此这篇关于redis:缓存穿透、缓存击穿与缓存雪崩的文章就介绍到这了,更多相关redis缓存穿透、缓存击穿与缓存雪崩内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论