Redis 缓存三大问题实战:穿透、击穿、雪崩

📅 2026/7/11 5:51:00
Redis 缓存三大问题实战:穿透、击穿、雪崩
日期2025-08-15 | 作者枝莺 | 分类后端开发问题背景暑假在开发记者团设备管理小程序时发现某些时间段接口响应特别慢。排查后发现是 Redis 缓存使用不当导致的。今天系统整理下缓存三大经典问题。1. 缓存穿透现象查询一个根本不存在的数据缓存中没有每次请求都打到数据库。用户查 id99999不存在 → 缓存没有 → 查数据库 → 数据库也没有 → 缓存不写 → 下次再来继续打数据库解决方案// 方案1: 缓存空值简单有效 public Device getDevice(Long id) { String key device: id; Device device (Device) redisTemplate.opsForValue().get(key); if (device ! null) return device; // 检查是否是缓存空值标记 String nullMark (String) redisTemplate.opsForValue().get(device:null: id); if (NULL.equals(nullMark)) return null; device deviceMapper.selectById(id); if (device ! null) { redisTemplate.opsForValue().set(key, device, 30, TimeUnit.MINUTES); } else { // 缓存空值短期过期 redisTemplate.opsForValue().set(device:null: id, NULL, 3, TimeUnit.MINUTES); } return device; }// 方案2: 布隆过滤器更优雅 Configuration public class BloomFilterConfig { Bean public BloomFilterLong deviceBloomFilter(DeviceMapper mapper) { ListLong allIds mapper.selectAllIds(); BloomFilterLong filter BloomFilter.create( Funnels.longFunnel(), allIds.size(), 0.01); allIds.forEach(filter::put); return filter; } }2. 缓存击穿现象热点key在过期瞬间大量并发请求同时打到数据库。热点key device:hot:100 过期 → 瞬间1000个请求同时查DB → 数据库压力暴增解决方案// 互斥锁最常用 public Device getHotDevice(Long id) { String key device:hot: id; Device device (Device) redisTemplate.opsForValue().get(key); if (device ! null) return device; // 加锁只有一个请求去查DB String lockKey lock:device: id; try { if (redisTemplate.opsForValue().setIfAbsent(lockKey, 1, 10, TimeUnit.SECONDS)) { // 双重检查 device (Device) redisTemplate.opsForValue().get(key); if (device ! null) return device; device deviceMapper.selectById(id); redisTemplate.opsForValue().set(key, device, 30, TimeUnit.MINUTES); return device; } else { // 没拿到锁等一会儿重试 Thread.sleep(100); return getHotDevice(id); // 递归重试 } } finally { redisTemplate.delete(lockKey); } }3. 缓存雪崩现象大量key在同一时间过期或者Redis挂了。解决方案过期时间加随机值EXPIRE random(0~300)秒多级缓存本地Caffeine RedisRedis 高可用哨兵/集群// 过期时间加随机 int expireTime 1800 ThreadLocalRandom.current().nextInt(300); redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS);总结问题根本原因核心方案穿透查不存在的数据布隆过滤器击穿热点key过期互斥锁雪崩大量key同时过期过期时间随机化这些方案在我自己的项目里全部落地了实际效果很好。特别是互斥锁方案把热点数据查询的DB压力从峰值1000QPS降到了1QPS。