
回复
什么是缓存穿透?
缓存穿透是指查询一个数据库中根本不存在的数据,导致每次请求都会穿过缓存直接访问数据库的现象。与缓存击穿(某个热点key失效时大量请求直接打到数据库)不同,缓存穿透是针对不存在的数据的持续高并发查询。
缓存穿透的危害
数据库压力剧增:大量请求直接穿透缓存层到达数据库
系统性能下降:数据库负载过高导致整体响应变慢
潜在服务崩溃风险:极端情况下可能导致数据库崩溃
资源浪费:无效查询消耗系统资源
缓存穿透的常见场景
恶意GJ:故意查询不存在的ID或参数
业务逻辑缺陷:未对参数做有效性校验
数据淘汰:已删除数据的持续查询
爬虫请求:爬取不存在的页面或数据
解决方案
public Object getData(String key) {
// 1. 从缓存查询
Object value = redis.get(key);
if (value != null) {
return value;
}
// 2. 缓存不存在,查询数据库
value = database.get(key);
if (value == null) {
// 数据库也不存在,缓存空值并设置较短过期时间
redis.setex(key, 60, "NULL"); // 60秒过期
return null;
}
// 3. 数据库存在,写入缓存
redis.setex(key, 3600, value); // 1小时过期
return value;
}
优点:实现简单,能有效阻挡重复的无效查询
缺点:可能缓存大量无用的空键,占用内存空间
// 初始化布隆过滤器
BloomFilter<String> bloomFilter = BloomFilter.create(
Funnels.stringFunnel(Charset.defaultCharset()),
1000000, // 预期元素数量
0.01); // 误判率
// 预热布隆过滤器
List<String> allKeys = database.getAllKeys();
for (String key : allKeys) {
bloomFilter.put(key);
}
public Object getData(String key) {
// 1. 先检查布隆过滤器
if (!bloomFilter.mightContain(key)) {
return null; // 肯定不存在
}
// 2. 布隆过滤器认为可能存在,继续正常流程
Object value = redis.get(key);
if (value != null) {
return value;
}
value = database.get(key);
if (value != null) {
redis.setex(key, 3600, value);
}
return value;
}
优点:内存效率高,能有效拦截绝对不存在的键
缺点:存在误判可能,需要预热,数据更新时需要同步更新过滤器
范围校验(如ID必须大于0)
业务规则校验(如手机号格式)
权限校验(如用户是否有权访问)
public Object getData(String key) {
Object value = redis.get(key);
if (value != null) {
return value;
}
// 尝试获取分布式锁
String lockKey = "lock:" + key;
boolean locked = redis.setnx(lockKey, "1", 10); // 10秒超时
if (!locked) {
// 获取锁失败,短暂等待后重试
Thread.sleep(100);
return getData(key);
}
try {
// 再次检查缓存,防止其他线程已经写入
value = redis.get(key);
if (value != null) {
return value;
}
value = database.get(key);
if (value == null) {
// 缓存空对象
redis.setex(key, 60, "NULL");
} else {
redis.setex(key, 3600, value);
}
return value;
} finally {
// 释放锁
redis.del(lockKey);
}
}
优点:避免大量并发请求同时穿透到数据库
缺点:实现复杂,可能增加系统延迟
最佳实践建议
组合使用多种方案:例如布隆过滤器+空对象缓存
监控与告警:监控缓存命中率,设置合理阈值
合理设置空值过期时间:通常比正常缓存短
热点数据特殊处理:对特别频繁的查询做特殊优化
定期清理无效空缓存:避免内存浪费
总结
缓存穿透是分布式系统中常见的高并发问题,通过合理的技术组合和预防措施,可以有效地减轻甚至消除其影响。在实际应用中,应根据业务特点选择最适合的方案或组合方案,并持续监控系统表现,不断优化防护策略。