1. 缓存穿透
缓存穿透是指查询-一个一定不存在的数据,由于缓存是丕命中,将去查询数据库,但
是数据库也无此记录,并且处于容错考虑,我们没有将这次查询的null写入缓存,这将
导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,
可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞.
解决方案:将null值或空字符串设置给redis
if (StringUtils.isNotBlank(skuJson)){
pmsSkuInfo = JSON.parseObject(skuJson, PmsSkuInfo.class);
}else {
//如果缓存中没有,查询mysql
pmsSkuInfo = getSkuByIdFromDb(skuId);
if (pmsSkuInfo!=null){
//mysql查询结果存入redis
jedis.set(skuKey,JSON.toJSONString(pmsSkuInfo));
}else {
//数据库中不存在该sku
//为了防止缓存穿透,将null值或空字符串设置给redis,并且设置一个短效的过期时间
jedis.setex(skuKey,60*3,JSON.toJSONString(""));
}
}
2. 缓存击穿
对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,
是一种非常“热点”的数据。这个时候,需要考虑-一个问题:如果这个key在大量请求
同时进来前正好失效,那么所有对这个key的数据查询都落到db,我们称为缓存击穿。
和缓存雪崩的区别:击穿是一个热点key失效,雪崩是很多key集体失效
解决方案:使用redis数据库的分布式锁解决mysql的访问压力问题
第一种分布式锁:redis自带一个分布式锁,set px nx
第二种分布式锁:redisson框架,一个redis的带有juc的lock功能的客户端的实现(既有jedis的功能,又有juc的锁功能)
详情请参考文档:Redisson