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

Redis缓存雪崩、击穿、穿透

缓存雪崩、缓存击穿、缓存穿透
这三个问题都发生在缓存失效或不存在时,大量请求直接涌向后端数据库,导致数据库压力激增甚至崩溃。

一、缓存雪崩 (Cache Avalanche)

1. 问题描述

同一时间大量的缓存Key集体失效(例如,设置了相同的过期时间),导致所有对这些数据的请求同时无法命中缓存(Cache Miss),全部直接落到数据库上,引起数据库瞬时压力过大而崩溃。

2. 发生场景

  • 业务高峰期,一批缓存数据(如首页商品列表、热门文章等)设置了相同的 TTL(Time-To-Live),同时过期。
  • Redis 服务宕机重启,导致整个缓存层不可用。

3. 解决方案

解决方案的核心是:避免大量Key同时失效

  1. 设置随机过期时间
    这是最简单有效的预防措施。给缓存数据的过期时间加上一个随机值,打散它们的失效时间点,避免集体失效。

    import random
    # 设置缓存时,在基础过期时间上增加一个随机抖动(例如0-300秒)
    expire_time = 3600 + random.randint(0, 300) # 1小时 ± 5分钟
    redis_client.setex(cache_key, expire_time, data)
    
  2. 构建高可用的Redis集群
    通过 Redis Sentinel(哨兵)或 Redis Cluster(集群)模式,实现主从切换和多节点负载均衡,即使单个节点宕机,整个缓存层依然可用,防止“全盘皆崩”。

  3. 缓存永不过期 + 后台更新
    对极热点数据,可以设置为永不过期(-1),然后由后台任务定时任务定期异步地更新缓存。这样用户请求永远不会遇到缓存失效。


二、缓存击穿 (Cache Breakdown)

1. 问题描述

一个访问量极高的热点Key(如某顶流明星的新闻、秒杀商品)在失效的瞬间,持续的高并发请求会像子弹一样“击穿”缓存,全部直接请求数据库,导致数据库瞬间压力过大。

2. 解决方案

解决方案的核心是:防止单个热点Key失效时被大量并发访问

  1. 互斥锁 (Mutex Lock) - 最常用
    当缓存失效时,不是所有请求都去查数据库,而是让第一个请求去查数据库并重建缓存,其他请求等待,待缓存重建后再从缓存中获取数据。

    import redis
    import threading
    from datetime import datetimedef get_data_with_lock(key):# 1. 先尝试从缓存获取data = redis_client.get(key)if data is not None:return data# 2. 缓存未命中,尝试获取分布式锁lock_key = f"lock:{key}"# 使用 setnx (SET if Not eXists) 命令争抢锁,并设置锁的过期时间(防止死锁)acquired_lock = redis_client.setnx(lock_key, datetime.now().strftime("%s"))if acquired_lock:redis_client.expire(lock_key, 10)  # 设置锁10秒后自动过期try:# 3. 成功获取锁,查询数据库data = get_data_from_db(key)# 4. 写入缓存redis_client.setex(key, 3600, data)finally:# 5. 释放锁redis_client.delete(lock_key)return dataelse:# 6. 未获取到锁,等待片刻后重试(或直接返回默认值)time.sleep(0.1)return get_data_with_lock(key)  # 重试
  2. 逻辑过期 (Logical Expiration)
    不给缓存设置 TTL,而是在缓存Value中存储一个逻辑过期时间。当请求发现逻辑时间已过期,则发起一个异步任务去更新缓存,当前请求仍返回旧数据。

    # Value 结构:{"data": real_data, "expire_ts": 1649873100}
    value = {"data": {"name": "Hot Product", "price": 99},"expire_ts": int(time.time()) + 3600  # 1小时后逻辑过期
    }
    redis_client.set(key, json.dumps(value)) # 不设置TTL# 读取时:
    cached_value = redis_client.get(key)
    if cached_value:obj = json.loads(cached_value)if obj['expire_ts'] > time.time():return obj['data']  # 未逻辑过期,直接返回else:# 已逻辑过期,触发异步更新async_update_cache(key)return obj['data']  # 仍然先返回旧数据
    

三、缓存穿透 (Cache Penetration)

1. 问题描述

请求查询一个数据库中根本不存在的数据(如 id=-1 的商品,或随机生成的、不存在的用户ID)。由于缓存中也不会有该数据,导致每次请求都会穿透缓存去查询数据库。如果有人恶意攻击,会发送大量此类请求,从而压垮数据库。

2. 解决方案

解决方案的核心是:在缓存层拦截掉对不存在数据的请求

  1. 缓存空对象 (Cache Null Object)
    即使从数据库没查到,也缓存一个空值(如 None, NULL)或特定的错误标记,并设置一个较短的过期时间(如 1-5 分钟)。后续相同的请求会命中这个空缓存,从而保护数据库。

    def get_data(key):data = redis_client.get(key)if data is not None:# 如果缓存的是空标记,直接返回None或错误if data == "NULL_OBJECT":return Nonereturn data# 查数据库data = db.query("SELECT * FROM table WHERE id = %s", key)if not data:# 数据库不存在,缓存空对象,有效期5分钟redis_client.setex(key, 300, "NULL_OBJECT")return Noneelse:# 数据库存在,写入缓存redis_client.setex(key, 3600, data)return data
    

缺点:如果攻击者每次用不同的Key,此方法会缓存大量无用的空值,浪费内存。

  1. 布隆过滤器 (Bloom Filter) - 最优解
    在缓存之前,设置一个布隆过滤器。它是一个概率型数据结构,用于快速判断一个元素是否绝对不存在于某个集合中
  • 写入时:当向数据库插入新数据时,同时将该数据的Key写入布隆过滤器。

  • 查询时:收到请求后,先用布隆过滤器判断Key是否存在。

    • 如果不存在,则直接返回 None,根本不会查询缓存和数据库。
    • 如果存在,再继续后续的缓存查询流程。
    # 使用 Redis 4.0+ 自带的布隆过滤器模块 (redisbloom)
    # 或者使用 Python 的 redisbloomclient 库from redisbloom.client import Clientrb = Client()
    key = "user:10000"# 1. 先检查布隆过滤器
    if not rb.bfExists("users_filter", key):print("Key definitely not exists, return directly.")return None# 2. 如果布隆过滤器说存在,再继续查缓存和数据库
    data = redis_client.get(key)
    if data:return data
    # ... (后续流程)
    

    优点:内存占用极小,效率极高。
    缺点:有极低的误判率(判断为存在,但实际可能不存在),但不会误判“不存在”。对于缓存穿透场景,宁可错杀一千(放过极少数不存在的请求去查库),也不能放过一个。

  1. 接口层增加校验
    对请求的参数做基础的合法性校验。例如,id 为负数的请求、非法的邮箱格式等,直接在入口层拦截并返回错误。
http://www.sczhlp.com/news/72048/

相关文章:

  • 批量将数字设置为文本格式
  • find方法的常见应用
  • CC++ 小结之位操作
  • 品牌 网站建设wordpress更换ssl
  • 网站对公司的作用是什么网上国网推广方案
  • wap网站建设流程可以做录音兼职的网站
  • 给中小企业提供网站建设服务做微信的微网站费用多少
  • 个体工商户经营范围做网站怎么做网站认证
  • 代码执行漏洞
  • mysql管理软件,三大MySQL图形化管理工具对比
  • 【SAE出版、EI稳定检索】第五届物流系统与交通运输国际学术会议(LSTT 2025)
  • 唐山有制作网站的没手表价格网站
  • xuzhou公司网站制作百度seo可能消失
  • dw做网站表格插不到右边网上机械加工厂
  • 头像代做网站佛山做网站-准度科技公司
  • 基于js原生的新闻类静态网站建设网站简易后台
  • 奇趣统计网站谁做的厦门建设局网站商品房
  • 网站建设和域名备案住房和城乡建设网站 上海
  • 做茶歇的网站网站建设怎样回答客户问题
  • 百度新网站收录深圳市路桥建设集团有限公司招标采购网站
  • Redis持久化
  • 2023年春季研究奖项获奖名单揭晓
  • 安卓版16音轨简谱编辑器软件说明
  • 丽水网站开发公司电话dede做视频网站
  • 一键制作单页网站给网站做引流多少钱
  • 做网站的uiwordpress excel 检索
  • 电子商务网站html模板百度下载官网
  • 怎么购买网站空间和域名钉钉怎么注册企业
  • 巩义企业网站建设杭州国家高新技术企业
  • 随机点名1