侧边栏壁纸
  • 累计撰写 1,773 篇文章
  • 累计收到 0 条评论

缓存策略

加速器之家
2025-07-21 / 0 评论 / 1 阅读 / 正在检测是否收录...

缓存穿透:当“查无此人”击垮你的数据库——防击穿实战指南

作为开发者,你是否经历过数据库在流量并不算高时却突然崩溃?明明用了Redis等缓存,性能瓶颈却依然诡异出现?这很可能就是缓存穿透在作祟——一个看似简单却能引发雪崩效应的隐形杀手。今天我们就来深入剖析它的成因,并提供实战级的防御方案。

一、缓存穿透:不只是缓存未命中

缓存的核心思想是“空间换时间”。理想流程如下:

  • 请求查询数据A → 先查缓存(命中则返回)
  • 缓存未命中 → 查数据库 → 结果写入缓存 → 返回数据

缓存穿透的致命之处在于: 攻击者或异常流量持续请求数据库中根本不存在的数据(如非法ID、负数值)。此时:

  • 缓存层永远无法命中(无数据可缓存)
  • 每次请求都直达底层数据库
  • 高并发下瞬间耗尽数据库连接资源 → 服务崩溃!

二、真实案例:电商平台的库存惊魂

某电商大促期间,监控告警显示MySQL连接数飙升至上限。经排查:

  • 攻击者利用脚本批量请求 productId=-1, 0, 999999 等非法商品ID
  • Redis中没有这些Key,请求全部穿透
  • 每秒数千次无效查询压垮了商品数据库集群

结果:核心交易链路瘫痪近10分钟,损失惨重。

三、防御武器库:四招化解危机

以下方案可组合使用,根据业务场景选择:

  1. 空值缓存(布设防线)

    即使数据库查无数据,也在缓存中存储一个短时效的空值(如 key: "product_99999", value: "NULL", TTL=5分钟)。伪代码示例:

    String data = redis.get(key);
    if (data != null) {
        return "NULL".equals(data) ? null : data; // 区分真实空与有效数据
    }
    data = db.query(key);
    if (data == null) {
        redis.setex(key, 300, "NULL"); // 缓存空值5分钟
        return null;
    }
    redis.setex(key, 3600, data); // 缓存真实数据1小时
    return data;
  2. 布隆过滤器(高效拦截器)

    原理: 使用一个超大的二进制位数组+多个哈希函数。将所有合法Key提前初始化到过滤器中。


    • 请求到来时,先用布隆过滤器判断Key是否存在:
    • 若报告“不存在” → 直接返回空,屏蔽数据库查询
    • 若报告“可能存在” → 继续走缓存/DB流程

    优势: 内存占用极低,时间复杂度O(1)。
    注意: 有极低误判率(报告存在但实际不存在),需定期重建。

  3. 接口层校验(第一道门禁)

    在Controller层或网关对参数做严格校验:


    • ID必须为正整数
    • 字符串长度/格式检查(如手机号、邮箱)
    • 直接拦截明显非法参数,减少无效请求穿透
  4. 限流降级(最后保险丝)

    为高频访问但缓存命中率极低的Key配置限流规则(如Sentinel/Nginx):


    • 每秒超过N次请求直接熔断
    • 返回默认值或友好错误提示

四、技术风向:RedisModule助力防御

Redis Labs推出的RedisBloom模块原生支持布隆过滤器,只需一条命令:

BF.ADD legitimate_keys product_123  # 添加合法Key
BF.EXISTS legitimate_keys product_999 # 检查是否存在(返回0表示一定不存在)

无需客户端实现,性能更高,已成为云数据库服务的标配功能。

结论:没有银弹,唯有组合拳

缓存穿透本质是非法请求对系统的暴力冲击。单一方案可能失效:空值缓存易被不同Key击穿,布隆过滤器需维护,参数校验有漏网之鱼。务必根据业务特点:

  • 核心服务:布隆过滤器 + 空值缓存 + 严格校验
  • 中低频业务:空值缓存 + 接口基础校验
  • 全局防护:网关层统一限流策略

记住:永远不要信任前端传入的参数。做好防御,让缓存真正成为性能加速器而非系统崩溃的导火索!

0

评论

博主关闭了当前页面的评论