面试官VS谢飞机:Spring Boot微服务中Redis缓存击穿的攻防实战

面试官VS谢飞机:Spring Boot微服务中Redis缓存击穿的攻防实战 面试官VS谢飞机Spring Boot微服务中Redis缓存击穿的攻防实战 场景导入本地生活服务的高并发挑战谢飞机同学你好请简单介绍一下你在本地生活服务平台的开发经验。您好我在XX生活平台负责外卖订单系统日均订单量超500万高峰期QPS达到12000...等等你说高峰期QPS 12000那你们怎么应对缓存击穿问题的谢飞机擦了擦额头的汗⚔️ 缓存击穿一场悄无声息的雪崩在本地生活服务中热门商家信息如海底捞、喜茶被高频访问但缓存过期时大量请求直接打到数据库造成DB压力飙升甚至宕机。// 危险的缓存读取方式 public Shop getShop(Long id) { String key shop: id; Shop shop redisTemplate.opsForValue().get(key); if (shop null) { // 缓存穿透击穿风险 shop shopMapper.selectById(id); redisTemplate.opsForValue().set(key, shop, 30, TimeUnit.MINUTES); } return shop; }️ 工业级防御方案方案1互斥锁Mutex Lockpublic Shop getShopWithMutex(Long id) { String key shop: id; String lockKey lock:shop: id; Shop shop redisTemplate.opsForValue().get(key); if (shop ! null) return shop; // 尝试获取锁 if (tryLock(lockKey)) { try { // 双重检查 shop redisTemplate.opsForValue().get(key); if (shop null) { shop shopMapper.selectById(id); redisTemplate.opsForValue().set(key, shop, 30, TimeUnit.MINUTES); } } finally { unlock(lockKey); } } else { // 等待后重试 Thread.sleep(50); return getShopWithMutex(id); } return shop; }方案2逻辑过期Logical Expirationpublic Shop getShopWithLogicalExpire(Long id) { String key shop:logic: id; RedisData redisData redisTemplate.opsForValue().get(key); if (redisData null) { return queryWithPassThrough(id); } // 判断是否逻辑过期 if (redisData.getExpireTime().isBefore(LocalDateTime.now())) { // 缓存重建 CACHE_REBUILD_EXECUTOR.submit(() - { try { rebuildCache(id); } catch (Exception e) { log.error(缓存重建失败, e); } }); } return redisData.getData(); } 方案对比| 方案 | 优点 | 缺点 | 适用场景 | |------|------|------|----------| | 互斥锁 | 实现简单数据一致性好 | 性能损耗可能造成请求阻塞 | 中低并发强一致性要求 | | 逻辑过期 | 性能最优无锁竞争 | 实现复杂可能有短暂不一致 | 高并发允许短暂不一致 | 最佳实践建议组合使用热点数据用逻辑过期关键数据用互斥锁监控告警建立缓存命中率、重建频率监控降级策略缓存重建失败时启用本地缓存降级预热机制业务低峰期预加载热点数据 谢飞机最终拿到了Offer他明白真正的技术深度不在于记住多少API而在于理解每个设计背后的权衡与思考。本文首发于CSDN转载请联系作者授权