一、缓存穿透
什么是穿透?
前提:模拟一个不存在的订单号xxx
1、Resi 中无此值
2、MySQL 中也我也此值,但是一直被查询
缓存层和持久层都不会命中,在日常工作中出于容错的考虑,如果从持久层查不到数据则不写入缓存层,缓存穿透将导致不存在的数据每次请求都要到持久层去查询,失去了缓存保护后端持久的意义。
解决方案:
1. 缓存空对象
缓存空对象:是指在持久层没有命中的情况下,对key进行set (key,null)
缓存空对象会有两个问题:
第一,value为null 不代表不占用内存空间,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间,比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。
第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象
2. 布隆过滤器拦截
对订单表所有数据查询出来放到布隆过滤器,经过布隆过滤器处理的数据很小(只存 0 或 1)
每次查订单表前,先到过滤器里查询当前订单号状态是0还是1, 0的话代表数据库没有数据,直接拒绝查询
缓存雪崩
什么是雪崩?
由于缓存层承载着大量请求,有效地保护了存储层,但是如果缓存层由于某些原因不可用(宕机)或者大量缓存由于超时时间相同在同一时间段失效(大批 key 失效/热点数据失效),大量请求直接到达存储层,存储层压力过大导致系统雪崩。
解决方案如下:
1、设置热点数据永远不过期。
2、加互斥锁,互斥锁参考代码如下
public static String getDate(String key) throws InterruptedExeception {
//从缓存中读取数据
String result = getDateFromRedis(key);
//缓存中不存在数据
if (null == result) {
//去获得锁,获取成功,去数据库获取数据
if (reenLock.tryLock()) {
//从数据库中获取数据
result = getDateFromMysql(key);
//更新缓存数据
if (null != result) {
setDataToCache(key, result);
}
//释放锁
reenLock.unlock();
}
//获取锁失败
else {
//暂停100ms再重新去获取数据
Thread.sleep(100);
retsult = getData(key);
}
}
return result;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/68386.html