Redis缓存穿透、缓存击穿、缓存雪崩、热点Key的示例分析

发布时间:2021-12-20 10:44:50 作者:小新
来源:亿速云 阅读:181
# 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;
}

1.3 解决方案

  1. 空值缓存:对不存在的数据也缓存空对象(需设置较短TTL)
// 改进代码
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);
}
  1. 布隆过滤器:预加载有效Key到布隆过滤器,先校验再查询
# 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

二、缓存击穿(Cache Breakdown)

2.1 概念与场景

某个热点Key突然过期时,大量并发请求直接击穿到数据库。典型场景: - 秒杀商品缓存过期 - 首页热门资讯缓存失效

2.2 示例现象

2.3 解决方案

  1. 互斥锁(Mutex Lock)
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);
    }
}
  1. 逻辑过期:实际缓存永不过期,通过额外字段控制逻辑过期时间
// 缓存数据结构
{
  "value": "真实数据",
  "expire_time": 1672502400 // 逻辑过期时间戳
}

三、缓存雪崩(Cache Avalanche)

3.1 概念与场景

大量Key同时过期或Redis集群宕机,导致请求全部涌向数据库。典型案例: - 凌晨批量任务刷新所有缓存 - Redis主从切换期间

3.2 解决方案

  1. 差异化过期时间
// 设置基础过期时间+随机偏移量
int baseExpire = 3600;
int randomExpire = new Random().nextInt(300);
redisTemplate.opsForValue().set(key, value, baseExpire + randomExpire, TimeUnit.SECONDS);
  1. 多级缓存架构
请求 → CDN → 本地缓存(Caffeine) → Redis → DB
  1. 熔断降级机制
# 伪代码示例
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

四、热点Key(Hot Key)

4.1 识别方法

4.2 解决方案

  1. 本地缓存+Redis多副本
// 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集群读取
        }
    });
  1. Key分片
# 将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)和动态配置中心实现策略的实时调整。 “`

推荐阅读:
  1. redis缓存穿透,缓存击穿,缓存雪崩原因+解决方案
  2. Redis高级应用解析:缓存穿透、击穿、雪崩

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

redis

上一篇:Zephyr OS 汇编阶段是怎样的

下一篇:arm9中断结构是怎样的

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》