您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Redis缓存穿透、缓存击穿、缓存雪崩、热点Key的示例分析
## 一、缓存穿透(Cache Penetration)
### 1.1 概念与场景
缓存穿透指**查询不存在的数据**,导致请求直接穿透缓存层到达数据库。常见场景:
- 恶意攻击:故意请求不存在的ID(如负值、超大数值)
- 业务误操作:前端传递无效参数(如已删除的商品ID)
### 1.2 示例代码
```java
// 错误示例:未做空值校验
public Product getProduct(Long id) {
// 1. 先查缓存
Product product = redisTemplate.opsForValue().get("product:" + id);
if (product == null) {
// 2. 缓存未命中,直接查库
product = productMapper.selectById(id); // 可能返回null
redisTemplate.opsForValue().set("product:" + id, product);
}
return product;
}
// 改进代码
if (product == null) {
product = productMapper.selectById(id);
if (product == null) {
redisTemplate.opsForValue().set("product:" + id, "NULL", 5, TimeUnit.MINUTES);
return null;
}
redisTemplate.opsForValue().set("product:" + id, product);
}
# Python示例
from pybloom_live import ScalableBloomFilter
bf = ScalableBloomFilter(initial_capacity=1000)
# 预热阶段加载所有有效ID
for id in valid_ids:
bf.add(id)
# 查询前校验
if not id in bf:
return None
某个热点Key突然过期时,大量并发请求直接击穿到数据库。典型场景: - 秒杀商品缓存过期 - 首页热门资讯缓存失效
public Product getProductWithLock(Long id) {
String lockKey = "lock:product:" + id;
try {
// 尝试获取分布式锁
Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (locked) {
Product product = productMapper.selectById(id);
redisTemplate.opsForValue().set("product:" + id, product, 1, TimeUnit.HOURS);
return product;
} else {
Thread.sleep(100); // 短暂等待后重试
return getProductWithLock(id);
}
} finally {
redisTemplate.delete(lockKey);
}
}
// 缓存数据结构
{
"value": "真实数据",
"expire_time": 1672502400 // 逻辑过期时间戳
}
大量Key同时过期或Redis集群宕机,导致请求全部涌向数据库。典型案例: - 凌晨批量任务刷新所有缓存 - Redis主从切换期间
// 设置基础过期时间+随机偏移量
int baseExpire = 3600;
int randomExpire = new Random().nextInt(300);
redisTemplate.opsForValue().set(key, value, baseExpire + randomExpire, TimeUnit.SECONDS);
请求 → CDN → 本地缓存(Caffeine) → Redis → DB
# 伪代码示例
def get_data(key):
if circuit_breaker.is_open():
return get_data_from_backup()
try:
data = redis.get(key)
if not data:
data = db.query(key)
redis.setex(key, ttl, data)
return data
except Exception as e:
circuit_breaker.record_failure()
raise e
// Guava本地缓存
LoadingCache<String, Product> localCache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.SECONDS)
.build(new CacheLoader<String, Product>() {
@Override
public Product load(String key) {
return getFromRedis(key); // 从Redis集群读取
}
});
# 将hot_key拆分为hot_key_1, hot_key_2...
shard_id = hash(user_id) % 4
real_key = f"hot_key_{shard_id}"
redis.get(real_key)
问题类型 | 核心特征 | 典型解决方案 |
---|---|---|
缓存穿透 | 查询不存在数据 | 布隆过滤器、空值缓存 |
缓存击穿 | 单热点Key失效 | 互斥锁、逻辑过期 |
缓存雪崩 | 大量Key同时失效 | 差异化TTL、多级缓存 |
热点Key | 单Key访问量极高 | 本地缓存、Key分片 |
实际生产环境中,建议结合监控系统(如Prometheus)和动态配置中心实现策略的实时调整。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。