您的位置:首页 > 财经 > 金融 > 义乌企业网站设计_生产erp管理系统app_代理推广月入5万_爱网站关键词挖掘工具

义乌企业网站设计_生产erp管理系统app_代理推广月入5万_爱网站关键词挖掘工具

2024/12/22 12:28:20 来源:https://blog.csdn.net/qq_63981644/article/details/143647357  浏览:    关键词:义乌企业网站设计_生产erp管理系统app_代理推广月入5万_爱网站关键词挖掘工具
义乌企业网站设计_生产erp管理系统app_代理推广月入5万_爱网站关键词挖掘工具

欢迎来到“雪碧聊技术”CSDN博客!

在这里,您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者,还是具有一定经验的开发者,相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导,我将不断探索Java的深邃世界,分享最新的技术动态、实战经验以及项目心得。

让我们一同在Java的广阔天地中遨游,携手提升技术能力,共创美好未来!感谢您的关注与支持,期待在“雪碧聊技术”与您共同成长!

目录

一、缓存雪崩

1、什么是缓存雪崩?

2、解决方案

二、缓存击穿

1、什么是缓存击穿?

2、解决方案

①互斥锁

②逻辑过期

3、对比两种方案

4、案例:基于“互斥锁”,解决缓存击穿问题

​编辑

①如何实现互斥锁呢?

②编写代码

③重启项目,使用Jmeter工具测试该后端接口

5、案例:基于“逻辑过期”,解决缓存击穿问题


一、缓存雪崩

1、什么是缓存雪崩?

缓存雪崩:是指在同一时段,大量的缓存key同时失效或者Redis服务宕机,导致大量请求打到数据库,带来巨大压力。

2、解决方案

二、缓存击穿

1、什么是缓存击穿?

        缓存击穿:也叫热点key问题,就是一个被高并发访问缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间打到数据库,给数据库带来巨大的压力。

        举例:热点key的TTL突然到期了,线程1从redis中没命中,然后去数据库查询,并将数据重新写会redis(由于该热点key的缓存重建业务较复杂,因此重建时间比较久),在重建期间,由于该热点key是高并发的,因此此时无数线程请求该key,redis没命中,于是这些请求都打到数据库,导致数据库压力巨大。

2、解决方案

①互斥锁

核心思想:线程1发现redis不存在该热点key,于是获取互斥锁,然后查询数据库并重建该缓存,等把该热点key的缓存成功写到了redis中,才会释放这个互斥锁。这期间,其他线程,查询redis也没命中,于是也尝试获取互斥锁,但是获取失败了(因为互斥锁被线程1占用),于是无法进行查询数据库并重建缓存的动作,于是只能等待。等到线程1重建好缓存,才能命中。

优点:缓存和数据库,是数据一致的。

缺点:其他线程需要等待,导致性能不佳(服务可用性差)。

②逻辑过期

核心思想:往redis存数据时,我就不设置TTL,于是该热点key永远不会过期,因此不可能出现热点key失效的现象。

但是为了保证缓存、数据库的数据一致性,因此还是要往热点key的value当中添加一个逻辑过期时间,每次访问该热点缓存时,都要主动判断是否过期,如果过期,就获取互斥锁,然后开启一个新线程(等于叫来一个帮手),帮我去完成缓存重建的动作,我自己这个线程还是返回旧的缓存,这样的确有点数据不一致,但是也无伤大雅。

优点:无需等待,性能好(服务可用性好)。

缺点:导致轻微的数据不一致问题。

3、对比两种方案

综上:这两种方式的数据一致性、服务可用性(性能)不可兼得。

一致性和可用性的抉择,也是分布式系统里面,常常面临的一个问题。

这两种,也没有孰优孰劣,应当根据应用场景来进行抉择。

4、案例:基于“互斥锁”,解决缓存击穿问题

①如何实现互斥锁呢?

我们此处借助redis的机制,来实现互斥锁。

也就是,我们获取互斥锁时,就执行setnx lock 1,即:向redis中,添加一个key为lock,value为1的键值对;释放互斥锁时,就执行del lock,即:将key为lock的数据删除。

②编写代码

先编写获取、释放互斥锁的方法。

注意:redis中的setnx命令,对应stringRedisTemplate中的setIfAbsent方法。

    //自定义方法:获取互斥锁private boolean tryLock(String key){Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);return BooleanUtil.isTrue(flag);//防止Boolean自动拆箱成boolean时出现空指针异常}//自定义方法:释放互斥锁private void unlock(String key){stringRedisTemplate.delete(key);}

编写“互斥锁”解决缓存击穿的代码(带*号的,是本次要学的)

    @Overridepublic Result queryById(Long id) {String key = CACHE_SHOP_KEY + id;//1、从Redis中查询商铺缓存String shopJson = stringRedisTemplate.opsForValue().get(key);//2、判断redis是否存在if(StrUtil.isNotBlank(shopJson)){//3、存在,则直接返回Shop shop = JSONUtil.toBean(shopJson, Shop.class);return Result.ok(shop);}//判断命中的是否是空值if(shopJson != null && shopJson.equals("")){//返回一个错误信息return Result.fail("店铺信息不存在!防止缓存穿透!");}//4、redis中不存在,进行缓存重建 *//4.1获取互斥锁 *String lockKey = "lock:shop:"+id;Shop shop = null;try {boolean isLock = tryLock(lockKey);//4.2判断是否获取成功 *if(!isLock){//4.3失败,则休眠并重试查询redis *Thread.sleep(50);return queryById(id);//递归本方法,表示重新查询redis}//4.4成功,根据id查询数据库 *shop = getById(id);//该方法,来自mybatisPlus//模拟重建缓存的延时 *Thread.sleep(200);//5、数据库也不存在,返回错误 *if(shop == null){//将空值写入redisstringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);return Result.fail("店铺不存在!");}//6、数据库中存在,则写入redis,并返回给前端 *stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES);} catch (InterruptedException e) {throw new RuntimeException(e);} finally {//7、释放互斥锁 *unlock(lockKey);}if(shop==null){ //*return Result.fail("店铺不存在!");}//8、返回return Result.ok(shop);}

③重启项目,使用Jmeter工具测试该后端接口

可见此时没毛病,使用“互斥锁”的方式,成功解决了“缓存击穿”的问题。

5、案例:基于“逻辑过期”,解决缓存击穿问题

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com