1. 缓存击穿场景下的攻防对抗本质
在分布式系统架构中,缓存击穿(Cache Breakdown)是指某个热点key在缓存过期瞬间,突发大量请求直接穿透到数据库的现象。这种场景下,面试官扮演流量洪峰的攻击方,谢飞机则作为系统架构的防守方,双方围绕三个核心维度展开博弈:
- 瞬时并发量级:攻击方通过模拟突发流量制造压力峰值
- 失效时间精度:防守方对缓存过期策略的精确控制能力
- 降级方案完备性:系统在极端情况下的自我保护机制
2. 攻击方战术手册解析
2.1 时间窗口精准打击
攻击方通常会采用以下手段制造缓存击穿:
// 模拟并发请求工具类 public class AttackSimulator { private static final int THREAD_COUNT = 1000; private static final CountDownLatch LATCH = new CountDownLatch(1); public void fireRequests(String targetKey) { ExecutorService pool = Executors.newFixedThreadPool(THREAD_COUNT); for (int i = 0; i < THREAD_COUNT; i++) { pool.execute(() -> { try { LATCH.await(); getFromDB(targetKey); // 模拟缓存未命中 } catch (Exception e) { Thread.currentThread().interrupt(); } }); } LATCH.countDown(); pool.shutdown(); } }2.2 热点数据识别技术
攻击方通过以下特征识别潜在攻击目标:
- 访问频率监控(如Redis的hotkeys命令)
- 业务维度分析(秒杀商品、首页推荐等)
- 缓存TTL模式识别(固定过期时间的缓存项)
3. 防守方防御体系构建
3.1 互斥锁实现方案
public class CacheProtector { private final RedissonClient redisson; public Object getData(String key) { Object value = redisTemplate.opsForValue().get(key); if (value == null) { RLock lock = redisson.getLock(key + "_lock"); try { if (lock.tryLock(3, 10, TimeUnit.SECONDS)) { value = dbQuery(key); redisTemplate.opsForValue().set(key, value, 30, TimeUnit.MINUTES); } else { Thread.sleep(50); return getData(key); // 递归重试 } } finally { lock.unlock(); } } return value; } }3.2 多级缓存策略
构建层级化防御体系:
- L1:本地Caffeine缓存(100ms级别TTL)
- L2:Redis集群缓存(分钟级TTL)
- L3:布隆过滤器(拦截非法key请求)
4. 进阶防御方案实现
4.1 异步刷新机制
@Scheduled(fixedRate = 60000) public void refreshHotKeys() { hotKeyList.forEach(key -> { CompletableFuture.runAsync(() -> { Object value = dbQuery(key); redisTemplate.opsForValue().set(key, value, 2, TimeUnit.HOURS); }); }); }4.2 熔断降级配置
# Resilience4j配置示例 resilience4j.circuitbreaker: instances: dbCircuitBreaker: registerHealthIndicator: true failureRateThreshold: 50 minimumNumberOfCalls: 10 automaticTransitionFromOpenToHalfOpenEnabled: true waitDurationInOpenState: 5s5. 实战性能对比测试
通过JMeter模拟不同防御策略下的系统表现:
| 防御策略 | QPS | 平均响应时间 | DB负载 |
|---|---|---|---|
| 无防护 | 12500 | 320ms | 100% |
| 互斥锁 | 8500 | 110ms | 2% |
| 多级缓存 | 14200 | 65ms | 0.5% |
| 异步刷新+熔断 | 16800 | 48ms | 0.1% |
6. 生产环境部署要点
- 锁粒度控制:采用分段锁降低争用(如商品ID取模分片)
- 监控埋点:
- 缓存命中率监控
- 锁等待时间监控
- DB查询QPS告警
- 压测方案:
- 影子库压测
- 故障注入测试(Chaos Engineering)
7. 典型问题排查实录
Case 1:锁失效导致DB查询翻倍
- 现象:互斥锁场景下DB查询量仍较高
- 根因:未设置锁过期时间导致死锁
- 修复:增加lock.tryLock()的超时控制
Case 2:缓存雪崩连锁反应
- 现象:多个热点key同时失效引发系统瘫痪
- 根因:缓存TTL设置过于集中
- 修复:基础TTL + 随机抖动时间(TTL ± 10%)
关键经验:任何防御方案都需要配合对应的监控指标,没有度量就无法优化