当前位置: 首页 > article >正文

Redis 缓存穿透、雪崩和击穿问题及解决方案

Redis 缓存穿透、雪崩和击穿问题及解决方案

在使用 Redis 作为缓存时,可能会遇到 缓存穿透缓存雪崩缓存击穿 这三种常见问题,它们都会影响系统的稳定性和性能。下面详细讲解它们的定义、成因以及相应的解决方案。


1. 缓存穿透(Cache Penetration)

1.1 定义

缓存穿透指的是查询的数据在缓存和数据库中都不存在,导致每次请求都会直接访问数据库,进而对数据库造成很大压力。

1.2 产生原因

  1. 恶意攻击:攻击者有意构造大量不存在的 key 来请求,绕过缓存直接访问数据库。
  2. 程序错误:业务代码逻辑有漏洞,导致频繁访问数据库中没有的数据。

1.3 解决方案

  1. 缓存空值(推荐)

    • 当数据库查询结果为空时,将该 key 对应的值设置为 NULL默认值 并存入缓存,设置一个短暂的过期时间(如 1 分钟)。
    • 例如:
      value = redis.get(key)
      if value is None:
          value = db.query(key)
          if value is None:
              redis.set(key, "NULL", ex=60)  # 设置 1 分钟过期
          else:
              redis.set(key, value, ex=3600)  # 设置 1 小时过期
      
  2. 布隆过滤器(Bloom Filter)

    • 使用布隆过滤器存储所有可能存在的 key,在查询缓存和数据库之前,先检查 key 是否可能存在。
    • 例如:
      from bloom_filter import BloomFilter
      bf = BloomFilter(capacity=100000, error_rate=0.01)
      bf.add("existing_key")  # 添加已有 key
      if key not in bf:
          return None  # 直接返回,避免访问 Redis 和数据库
      
  3. 参数校验与拦截

    • 在业务逻辑层对 key 进行基本的格式校验,避免恶意构造的请求直接进入数据库查询。

2. 缓存雪崩(Cache Avalanche)

2.1 定义

缓存雪崩指的是大量缓存数据同时失效,导致瞬间大量请求涌向数据库,造成数据库负载过高甚至宕机。

2.2 产生原因

  1. 大量数据设置了相同的过期时间,导致缓存同时过期。
  2. Redis 故障或宕机,导致所有缓存数据失效。

2.3 解决方案

  1. 缓存过期时间加随机值(推荐)

    • 例如:
      import random
      redis.set(key, value, ex=3600 + random.randint(1, 600))  # 过期时间 3600~4200 秒
      
  2. 双层缓存策略

    • 设立两级缓存:
      • 一级缓存(Redis)
      • 二级缓存(本地缓存,如 Guava Cache 或 EhCache)
    • 当 Redis 失效时,查询本地缓存,减少数据库压力。
  3. 热点数据提前预热

    • 在大规模活动(如秒杀、促销)前,提前加载热点数据到缓存,防止瞬时大规模请求击穿缓存。
  4. 降级与限流

    • 在缓存失效导致数据库压力激增时:
      • 限流:限制请求速率,如 令牌桶漏桶算法
      • 降级:返回默认值、缓存旧数据、提示用户稍后重试。

3. 缓存击穿(Cache Breakdown)

3.1 定义

缓存击穿指的是某个热点 key 失效后,大量请求同时访问数据库,造成数据库瞬时压力过大。

3.2 产生原因

  1. 某些热点数据访问量极高,一旦该 key 过期,瞬时大量请求直接访问数据库。
  2. 并发查询同一 key,导致大量请求同时击穿缓存。

3.3 解决方案

  1. 设置热点数据永不过期(推荐)

    • 例如:
      redis.set("hot_key", value, ex=None)  # 不设置过期时间
      
  2. 互斥锁(分布式锁)

    • 例如:
      import time
      import redis
      
      client = redis.StrictRedis()
      
      def get_value_with_lock(key):
          value = client.get(key)
          if value is None:  # 缓存失效
              lock = client.setnx(f"lock:{key}", 1)  # 尝试加锁
              if lock:
                  client.expire(f"lock:{key}", 10)  # 设置锁超时时间
                  value = db.query(key)  # 查询数据库
                  client.set(key, value, ex=3600)  # 写入缓存
                  client.delete(f"lock:{key}")  # 释放锁
              else:
                  time.sleep(0.1)  # 等待一段时间后再查缓存
                  return get_value_with_lock(key)
          return value
      
  3. 异步更新缓存

    • 采用异步线程消息队列来更新缓存,避免数据库查询被并发请求阻塞。

总结

问题定义解决方案
缓存穿透查询数据在缓存和数据库中都不存在,导致所有请求都打到数据库缓存空值、布隆过滤器、参数校验
缓存雪崩大量 key 同时过期或 Redis 故障,导致数据库瞬时压力过大过期时间加随机值、双层缓存、预热数据、限流降级
缓存击穿热点 key 过期后,大量并发请求直接访问数据库热点数据永不过期、互斥锁、异步更新缓存

如果你的系统涉及大规模并发访问,那么就要考虑这些缓存问题,并采用合适的策略来防止性能瓶颈! 🚀


http://www.kler.cn/a/517237.html

相关文章:

  • javaSE.类的继承
  • ray.rllib 入门实践-2:配置算法
  • 【EXCEL_VBA_实战】多工作薄合并深入理解
  • 微信小程序中常见的 跳转方式 及其特点的表格总结(wx.navigateTo 适合需要返回上一页的场景)
  • mysql 学习2 MYSQL数据模型,mysql内部可以创建多个数据库,一个数据库中有多个表;表是真正放数据的地方,关系型数据库 。
  • PL/SQL语言的图形用户界面
  • JAVAweb学习日记(七) 分层解耦
  • 软件需求工程中的风险管理
  • C语言-----扫雷游戏
  • 一款专业通用开源的MES生产执行管理系统
  • Unity常用特性(Attribute)用法
  • 睡眠时间影响因素K-Means可视化分析+XGBoost预测
  • 第15个项目:一个有趣的豆瓣电影TOP爬虫
  • ISIS基础知识
  • 2024-2025自动驾驶技术演进与产业破局的深度实践——一名自动驾驶算法工程师的年度技术总结与行业洞察
  • 基于SpringBoot+Vue的智慧动物园管理系统的设计与实现
  • 智能运维分析决策系统:赋能数字化转型的智慧引擎
  • qt 设置鼠标样式的几种方法
  • ceph新增节点,OSD设备,标签管理(二)
  • 付费会员制与开源AI智能名片S2B2C商城小程序在现代营销中的应用
  • 八股学习 微服务篇
  • 【Ubuntu】使用远程桌面协议(RDP)在Windows上远程连接Ubuntu
  • AI Agent的记忆系统实现:从短期对话到长期知识
  • React Native 0.77发布,新样式特性,Android 16KB页面支持,Swift模板
  • Vue 使用moment格式化时间
  • Meta的AIGC视频生成模型——Emu Video