Redis 缓存击穿问题 解决方案(二) 逻辑过期 您所在的位置:网站首页 redis缓存时间怎么设置 Redis 缓存击穿问题 解决方案(二) 逻辑过期

Redis 缓存击穿问题 解决方案(二) 逻辑过期

2023-09-02 23:50| 来源: 网络整理| 查看: 265

Redis 缓存击穿问题 解决方案(二) 逻辑过期

​ 逻辑过期方案:用户查询某个热门产品信息,如果缓存未命中(即信息为空),则直接返回空,不去查询数据库。如果缓存信息命中,则判断是否逻辑过期,未过期返回缓存信息,过期则重建缓存,尝试获得互斥锁,获取失败则直接返回已过期缓存数据,获取成功则开启独立线程去重构缓存然后直接返回旧的缓存信息,重构完成之后就释放互斥锁。

​ 这样看来,只要命中了缓存,无论是否过期,是否获得锁看,都返回同一个缓存信息。

​ 逻辑过期 的流程图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2lpmbyhV-1664181525415)(C:\Users\zhuhuanjie\AppData\Roaming\Typora\typora-user-images\image-20220910112759246.png)]

​ 查询某个热门产品信息的方法,如下。

@Override public Result queryById(Long id) { //缓存穿透 //Shop shop = queryWithPassThrough(id); //互斥锁解决缓存击穿 //Shop shop = queryWithMutex(id); //逻辑过期解决缓存击穿 Shop shop = queryWithLogicalExpire(id); if (shop == null) { return Result.fail("店铺不存在!"); } //返回 return Result.ok(shop); }

​ 这里解决 缓存击穿 问题的主要业务方法写在了 queryWithLogicalExpire(id) 中,完整代码如下:

//逻辑过期 public Shop queryWithLogicalExpire(Long id) { String key = CACHE_SHOP_KEY + id; //1.从redis查询商铺缓存 String shopJson = stringRedisTemplate.opsForValue().get(key); //2.判断是否存在 if (StrUtil.isBlank(shopJson)) { //3.未命中 return null; } //4.命中,需要先把json反序列化为对象 RedisData redisData = JSONUtil.toBean(shopJson, RedisData.class); Shop shop = (Shop) redisData.getData(); LocalDateTime expireTime = redisData.getExpireTime(); //5.判断是否过期 if (expireTime.isAfter(LocalDateTime.now())) { //5.1还未过期 return shop; } //5.2已经过期,需要缓存重建 //6.缓存重建 //6.1获取互斥锁 String lockKey = LOCK_SHOP_KEY + id; boolean isLock = tryLock(lockKey); //6.2判断是否获取锁成功 if (isLock) { // 6.3成功,开启独立线程,实现缓存重建 CACHE_REBUILD_EXECUTOR.submit(() -> { try { //重建缓存 this.saveShop2Redis(id, 20L); } catch (Exception e) { e.printStackTrace(); } finally { //释放锁 unlock(lockKey); } }); } //6.4返回过期的店铺信息 //7.返回 return shop; }

​ 由于线程获得锁之后要开启独立线程去重构缓存信息,那么我们最好提前声明定义一个线程池。

//线程池 private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);

​ 除了线程池外,我们还需要 获得锁 和 释放锁 的方法,具体代码如下:

//获得锁 private boolean tryLock(String key) { Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS); return BooleanUtil.isTrue(flag); } //释放锁 private void unlock(String key) { stringRedisTemplate.delete(key); }

​ 至此,利用 逻辑过期 解决缓存击穿问题就结束了。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有