3.分布式缓存(击穿、雪崩、穿透)
2019-12-09 本文已影响0人
指尖架构141319
1.概念示意图
1.1缓存击穿
- 概念:
缓存中没有但数据库中有的数据(一般是某一个key缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力 瞬间增大,造成过大压力 -
示意图:
image.png
1.2缓存雪崩
- 概念:
缓存中数据大批量key到过期时间,而查询数据量巨大,引起数据库压力过大甚至 down 机。
和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。 -
示意图:
image.png
1.3缓存穿透
- 概念:
缓存和数据库中都没有的数据,而用户不断发起请求,如发起为 id 为“-1”的数据或 id 为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导 致数据库压力过大。 -
示意图:
image.png
2.解决方案
2.1 击穿和雪崩
- 加锁、限流
- 缓存预热(常用值,使用http接口预热错峰加载)
- 改被动失效为主动失效(什么时候失效,设计者控制)
加锁、限流代码实现:
if (valueWrapper != null) {//缓存中查询
logger.info("缓存中得到数据");
return (Provinces) (valueWrapper.get());
}
//2.加锁排队,阻塞式锁
doLock(provinceid);
try{//第二个线程进来了
//双重校验
valueWrapper = redisTemplate.get(provinceid);//第二个线程,能从缓存里拿到值?
if (valueWrapper != null) {
logger.info("缓存中得到数据");
return (Provinces) (valueWrapper.get());//第二个线程,这里返回
}
Provinces provinces = super.detail(provinceid);
// 3.从数据库查询的结果不为空,则把数据放入缓存中,方便下次查询
if (null != provinces){
cm.getCache(CACHE_NAME).put(provinceid, provinces);
}
return provinces;
}catch(Exception e){
return null;
}finally{
//释放锁
releaseLock(provinceid);
}
2.2缓存穿透
- 直接把查询的key和value写入缓存,并设置失效时间(量大有风险)
- 布隆过滤器
- 或者放一个大的map存储查询