1. 先来认识缓存穿透的"犯罪现场"

假设我们运营一个日活百万的电商平台,某天突然发现数据库CPU飙升到90%。检查日志发现大量类似这样的请求:

SELECT * FROM products WHERE id = -123456789

这种明显不存在的数据请求绕过了Redis缓存层(因为缓存未命中),直接穿透到数据库,这就是典型的缓存穿透攻击场景。数据库每秒处理数千次无效查询,最终导致服务雪崩。


2. 防御武器库

武器一:布隆过滤器哨兵(Java+Redisson实现)

// 初始化布隆过滤器(Redisson客户端)
RBloomFilter<String> bloomFilter = redisson.getBloomFilter("productFilter");
// 预期数据量100万,误判率0.1%
bloomFilter.tryInit(1000000L, 0.001);

// 预热阶段:加载合法ID
for (Product product : productDao.findAll()) {
    bloomFilter.add(product.getId());
}

// 查询拦截
public Product getProduct(String id) {
    if (!bloomFilter.contains(id)) { // 布隆过滤器拦截
        return null; // 直接拦截非法请求
    }
    // 后续正常查询逻辑...
}

优势:内存占用极低(百万数据仅需约1MB),拦截效率高
注意事项:需要定期同步数据库更新,误判率需根据业务调整

武器二:空值缓存战术(SpringBoot示例)

@Cacheable(value = "products", key = "#id", 
           unless = "#result == null") // 不缓存null值
public Product getProduct(String id) {
    Product product = productDao.findById(id);
    if (product == null) {
        // 缓存空值(设置短过期时间)
        redisTemplate.opsForValue().set("empty:"+id, "", 5, TimeUnit.MINUTES);
    }
    return product;
}

@Cacheable(value = "emptyProducts", key = "#id", 
           condition = "#id.startsWith('empty:')")
public String checkEmpty(String id) {
    return null; // 直接返回空值缓存
}

适用场景:业务允许短暂空值显示的场合
注意事项:需预防恶意制造大量空键导致内存溢出


3. 实时监控作战室搭建

监控方案一:Redis慢查询分析

slowlog-log-slower-than 1000 # 记录超过1ms的查询
slowlog-max-len 1000        # 保留1000条记录

# 实时监控脚本
redis-cli slowlog get | grep 'get product:'

通过分析高频缓存取命令,识别异常访问模式

监控方案二:Prometheus+Granafa可视化

# prometheus.yml配置
scrape_configs:
  - job_name: 'redis_exporter'
    static_configs:
      - targets: ['redis_exporter:9121']

监控指标包括:

  • redis_missed_keys 统计缓存未命中率
  • redis_hits_rate 缓存命中率
  • command_call_count 命令调用排行

4. 进阶防御组合技

战术组合:布隆过滤器+本地缓存

// Caffeine本地缓存(Google Guava类似)
LoadingCache<String, Boolean> localCache = Caffeine.newBuilder()
    .maximumSize(10_000)
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .build(key -> bloomFilter.contains(key));

public boolean isValidId(String id) {
    return localCache.get(id); // 双重缓存校验
}

优势:减少网络IO消耗,提升拦截速度
注意事项:需处理分布式环境的一致性同步问题


5. 应用场景分析

  1. 电商库存系统:秒杀场景中恶意刷不存在的商品ID
  2. 社交网络:遍历不存在的用户ID获取信息
  3. 物联网设备:伪造非法设备ID获取连接凭证

6. 技术选型对比表

方案 内存消耗 误判率 实现复杂度 适用场景
布隆过滤器 0.1%-1% 海量数据场景
空值缓存 数据离散场景
互斥锁 高并发更新场景
请求合并 热点数据场景

7. 防御体系构建原则

  1. 分层防御:在Nginx层做基础校验,应用层做逻辑校验,缓存层做最终防御
  2. 动态调整:根据监控数据自动调整布隆过滤器误判率
  3. 熔断机制:当数据库压力超过阈值时,自动开启验证码校验

8. 特别注意事项

  1. 热点Key处理:对类似-1、0等特殊值要做特殊过滤
  2. 缓存雪崩预防:空值缓存的TTL要设置随机值(如5分钟±随机30秒)
  3. 监控盲区:注意统计穿透请求的客户端特征(如相同IP、UA等)

9. 未来演进方向

  1. 机器学习防御:基于历史请求模式训练异常检测模型
  2. WebAssembly应用:在边缘节点实现高性能过滤逻辑
  3. 量子加密技术:防御基于量子计算的暴力破解攻击