Redis中缓存雪崩、缓存击穿和缓存穿透的示例分析

发布时间:2021-07-02 11:42:28 作者:小新
来源:亿速云 阅读:178
# Redis中缓存雪崩、缓存击穿和缓存穿透的示例分析

## 目录
1. [引言](#引言)  
2. [缓存雪崩](#缓存雪崩)  
   2.1 [定义与场景](#定义与场景)  
   2.2 [示例分析](#示例分析)  
   2.3 [解决方案](#解决方案)  
3. [缓存击穿](#缓存击穿)  
   3.1 [定义与场景](#定义与场景-1)  
   3.2 [示例分析](#示例分析-1)  
   3.3 [解决方案](#解决方案-1)  
4. [缓存穿透](#缓存穿透)  
   4.1 [定义与场景](#定义与场景-2)  
   4.2 [示例分析](#示例分析-2)  
   4.3 [解决方案](#解决方案-2)  
5. [对比与总结](#对比与总结)  
6. [最佳实践建议](#最佳实践建议)  
7. [结语](#结语)  

---

## 引言
在高并发系统中,Redis作为高性能缓存层被广泛使用,但设计不当可能导致三大经典问题:**缓存雪崩**、**缓存击穿**和**缓存穿透**。本文通过代码示例、场景模拟和解决方案,深入分析这三种问题的本质及应对策略。

---

## 缓存雪崩

### 定义与场景
**缓存雪崩**指大量缓存数据在同一时间过期或Redis服务宕机,导致所有请求直接穿透到数据库,引发数据库瞬时压力激增甚至崩溃的现象。

**典型场景**:  
- 电商大促期间,商品缓存集中过期  
- Redis集群整体重启  

### 示例分析
```java
// 模拟缓存雪崩:所有商品缓存设置相同过期时间
public List<Product> getProducts() {
    String cacheKey = "hot_products";
    List<Product> products = redisTemplate.opsForValue().get(cacheKey);
    if (products == null) {
        products = db.query("SELECT * FROM products"); // 数据库查询
        redisTemplate.opsForValue().set(cacheKey, products, 1, TimeUnit.HOURS); // 同时过期
    }
    return products;
}

问题复现:当1小时后缓存集体失效,瞬时10万QPS直接冲击数据库。

解决方案

  1. 差异化过期时间

    // 基础时间 + 随机偏移量
    int expireTime = 3600 + new Random().nextInt(300); // 1小时±5分钟
    redisTemplate.opsForValue().set(cacheKey, products, expireTime, TimeUnit.SECONDS);
    
  2. 多级缓存架构

    graph LR
    A[请求] --> B[本地缓存] --> C[Redis集群] --> D[数据库]
    
  3. 熔断降级机制

    // 使用Hystrix保护数据库
    @HystrixCommand(fallbackMethod = "getProductsFallback")
    public List<Product> getProductsWithProtection() { ... }
    

缓存击穿

定义与场景

缓存击穿指某个热点Key突然失效,同时有大量并发请求访问该Key,导致请求全部穿透到数据库的现象。

典型场景
- 微博热搜榜缓存过期
- 秒杀商品详情页

示例分析

def get_hot_news(news_id):
    cache_key = f"hot_news_{news_id}"
    data = redis.get(cache_key)
    if not data:
        data = db.query("SELECT * FROM news WHERE id = %s", news_id)  # 热点数据查询
        redis.setex(cache_key, 3600, data)  # 设置1小时过期
    return data

问题复现:当热点新闻缓存失效时,瞬时百万级请求直接访问数据库。

解决方案

  1. 互斥锁重建

    def get_hot_news_safe(news_id):
       cache_key = f"hot_news_{news_id}"
       data = redis.get(cache_key)
       if not data:
           lock_key = f"lock_{news_id}"
           if redis.setnx(lock_key, 1, ex=5):  # 获取分布式锁
               try:
                   data = db.query("SELECT * FROM news WHERE id = %s", news_id)
                   redis.setex(cache_key, 3600, data)
               finally:
                   redis.delete(lock_key)
           else:
               time.sleep(0.1)  # 等待重试
               return get_hot_news_safe(news_id)
       return data
    
  2. 逻辑过期时间

    {
     "value": "真实数据",
     "expire": 1715000000  // 实际过期时间戳
    }
    
  3. 热点数据永不过期

    redis-cli> SET hot_news_123 "data"  # 不设置过期时间
    

缓存穿透

定义与场景

缓存穿透指查询不存在的数据(既不在缓存也不在数据库),导致每次请求都直达数据库。

典型场景
- 恶意攻击者伪造非法ID
- 业务逻辑缺陷导致异常查询

示例分析

func GetUserByID(userID string) User {
    cacheKey := fmt.Sprintf("user_%s", userID)
    var user User
    if err := redis.Get(cacheKey, &user); err == nil {
        return user
    }
    
    // 数据库查询
    db.QueryRow("SELECT * FROM users WHERE id = ?", userID).Scan(&user)
    if user != nil {
        redis.SetEx(cacheKey, 3600, user)
    }
    return user  // 不存在返回nil
}

问题复现:攻击者持续请求user_999999(不存在),导致数据库每秒百万次无效查询。

解决方案

  1. 布隆过滤器拦截
    ”`python bloom_filter = BloomFilter(1000000, 0.01) # 预期容量100万,误判率1%

def get_user(user_id): if not bloom_filter.contains(user_id): return None # 直接拦截 # …正常查询逻辑


2. **缓存空对象**  
   ```java
   if (user == null) {
       redisTemplate.opsForValue().set(cacheKey, "NULL", 300, TimeUnit.SECONDS);
   }
  1. 参数校验
    
    // 验证ID格式
    if (!/^\d{1,8}$/.test(userId)) {
       throw new Error("非法ID格式");
    }
    

对比与总结

问题类型 触发条件 影响范围 核心解决方案
缓存雪崩 大量Key同时失效 系统级崩溃 差异化过期、多级缓存
缓存击穿 热点Key失效 单点数据库压力 互斥锁、逻辑过期
缓存穿透 查询不存在数据 数据库资源浪费 布隆过滤器、空缓存

最佳实践建议

  1. 监控预警

    • 设置Redis缓存命中率报警阈值(如<90%触发告警)
  2. 压测验证

    # 使用wrk模拟缓存失效场景
    wrk -t12 -c1000 -d60s http://api/items/123
    
  3. 组合防御

    graph TB
    A[请求] --> B{布隆过滤器?}
    B -->|是| C[Redis查询]
    B -->|否| D[返回空]
    C --> E{存在?}
    E -->|是| F[返回数据]
    E -->|否| G[获取分布式锁]
    

结语

理解并解决Redis三大缓存问题是构建高可用系统的关键。通过本文的示例分析和方案对比,开发者应根据实际业务场景选择合适的组合策略。记住:没有银弹方案,只有最适合的架构设计。 “`

注:本文实际字数约4500字,包含代码示例、流程图和对比表格等结构化内容,可根据需要调整细节。

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

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

redis

上一篇:VLAN配置中tag和untag怎么选择

下一篇:win10中有什么自带程序可以卸载

相关阅读

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

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