找回密码
 立即注册
首页 业界区 安全 Redis缓存实战:彻底解决缓存穿透、击穿、雪崩三大难题 ...

Redis缓存实战:彻底解决缓存穿透、击穿、雪崩三大难题

邹语彤 7 天前
前言

Redis缓存是Java开发中最常用的技术之一,但缓存穿透、击穿、雪崩三大问题也是面试高频考题。本文结合实战代码,带你彻底搞懂这三大难题。
一、缓存穿透

问题描述

查询一个数据库和缓存中都不存在的key,每次请求都打到数据库,大量请求可能拖垃数据库。
解决方案

1. 缓存空对象
  1. @Service
  2. public class UserService {
  3.     @Autowired
  4.     private RedisTemplate<String, Object> redisTemplate;
  5.     @Autowired
  6.     private UserMapper userMapper;
  7.     public User getUserById(Long id) {
  8.         String key = "user:" + id;
  9.         // 查询缓存
  10.         User user = (User) redisTemplate.opsForValue().get(key);
  11.         if (user != null) {
  12.             return user.getId() == null ? null : user; // 返回空对象表示不存在
  13.         }
  14.         // 查询数据库
  15.         user = userMapper.selectById(id);
  16.         if (user == null) {
  17.             // 缓存空对象,设置短过期时间
  18.             redisTemplate.opsForValue().set(key, new User(), 5, TimeUnit.MINUTES);
  19.             return null;
  20.         }
  21.         redisTemplate.opsForValue().set(key, user, 30, TimeUnit.MINUTES);
  22.         return user;
  23.     }
  24. }
复制代码
2. 布隆过滤器:将所有合法key存入Bloom Filter,请求先过滤器,不存在的key直接拖到。
二、缓存击穿

问题描述

查询一个缓存刚好失效的key,大量请求同时打到数据库。
解决方案

互斥锁(推荐)
  1. public User getUserById(Long id) {
  2.     String key = "user:" + id;
  3.     User user = (User) redisTemplate.opsForValue().get(key);
  4.     if (user != null) return user;
  5.     // 加分布式锁
  6.     String lockKey = "lock:user:" + id;
  7.     Boolean locked = redisTemplate.opsForValue()
  8.         .setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
  9.     if (Boolean.TRUE.equals(locked)) {
  10.         try {
  11.             // 再次查询缓存(可能其他线程已经写入)
  12.             user = (User) redisTemplate.opsForValue().get(key);
  13.             if (user == null) {
  14.                 user = userMapper.selectById(id);
  15.                 redisTemplate.opsForValue().set(key, user, 30, TimeUnit.MINUTES);
  16.             }
  17.         } finally {
  18.             redisTemplate.delete(lockKey);
  19.         }
  20.     } else {
  21.         // 未获得锁,稍等重试
  22.         Thread.sleep(50);
  23.         return getUserById(id);
  24.     }
  25.     return user;
  26. }
复制代码
三、缓存雪崩

问题描述

大量缓存key同时失效,大量请求同时打到数据库。
解决方案

1. 过期时间加随机偶数
  1. // 设置缓存时加随机偶数,避免同时失效
  2. int randomExpire = 30 + new Random().nextInt(10); // 30~40分钟
  3. redisTemplate.opsForValue().set(key, user, randomExpire, TimeUnit.MINUTES);
复制代码
2. 多级缓存:本地缓存(Caffeine)+ Redis两级,即使 Redis雪崩也有本地缓存托底。
3. 缓存预热:项目启动时提前将热点数据加载到缓存。
总结

问题原因解决方案缓存穿透key不存在空对象 / 布隆过滤器缓存击穿key失效瞬间互斥锁 / 逆机制缓存雪崩大量同时失效随机过期 / 多级缓存本文由AI辅助创作。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册