一文参透:缓存一致性策略以及雪崩、穿透等问题(1)

redisTemplate.delete(entity.getId());

Dao.update(entity);

return entity;

}

public Entity add(Entity entity) {

redisTemplate.delete(entity.getId());

Dao.insert(entity);

return entity;

}

2. 缓存更新策略

适用于做缓存的场景一般都是:访问频繁、读场景较多而写场景少、对数据一致性要求不高。如果上面三个条件都不符合,那维护一套缓存数据的意义并不大了,实际应用中通常都需要针对业务场景来选择合适的缓存方案,下面给出了四种缓存策略,由上到下就是按照一致性由强到弱的顺序。

更新策略特点适用场景

实时更新同步更新保证强一致性,与业务强侵入强耦合金融转账业务等

若实时异步更新(MQ/发布订阅/观察者模式),业务解耦,若一致性存在延迟不适合写频繁场景

失效机制设置缓存失效,有一定延迟,可能存在雪崩适用读多写少,能接受一定的延时

任务调度通过定时任务进行全量更新统计类业务,访问频繁且定期更新

二. 缓存雪崩和击穿

==========

1. 缓存雪崩概念

缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。

解决方案

将缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。

第一种方案比较容易实现,第二种的思路主要是从加阻塞式的排它锁来实现,在缓存查询不到的情况下,每此只允许一个线程去查询DB,这样可避免同一个ID的大量并发请求都落到数据库中。

public Result query(String id) {

// 1.从缓存中取数据

Result result = null;

result = (Result)redisTemplate.opsForValue().get(id);

if (result ! = null) {

logger.info(“缓存中得到数据”);

return result;

}

//2.加锁排队,阻塞式锁

doLock(id);//多少个id就可能有多少把锁

try {

//一次只有一个线程

//双重校验,第一次获取到后面的都可以从缓存中直接击中

result = (Result)redisTemplate.opsForValue().get(id);

if (result != null) {

logger.info(“缓存中得到数据”);

return result;//第二个线程,这里返回

}

result = dao.query(id);

// 3.从数据库查询的结果不为空,则把数据放入缓存中,方便下次查询

if (null != result) {

redisTemplate.opsForValue().set(id,result);

redisTemplate.expire(id,20000, TimeUnit.MILLISECONDS);

}

return provinces;

} catch(Exception e) {

return null;

}

finally {

//4.解锁

releaseLock(provinceid);

}

}

private void releaseLock(String userCode) {

ReentrantLock oldLock = (ReentrantLock) locks.get(userCode);

if(oldLock !=null && oldLock.isHeldByCurrentThread()) {

oldLock.unlock();

}

}

private void doLock(String lockcode) {

//id有不同的值

//id相同的,加一个锁,不是同一个key,不能用同一个锁

ReentrantLock newLock = new ReentrantLock();//创建一个锁

//若已存在,则newLock直接丢弃

Lock oldLock = locks.putIfAbsent(lockcode, newLock);

if(oldLock == null) {

newLock.lock();

} else {

oldLock.lock();

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

面试题总结

其它面试题(springboot、mybatis、并发、java中高级面试总结等)

noe-1710404897483)]

面试题总结

其它面试题(springboot、mybatis、并发、java中高级面试总结等)

[外链图片转存中…(img-LkhDOFOc-1710404897484)]

[外链图片转存中…(img-CKhfE3oh-1710404897484)]

[外链图片转存中…(img-6ahPVVXJ-1710404897485)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值