背景
什么缓存击穿啊,穿透啊,雪崩啊,不管叫什么名字,本质上,基本上所有的缓存问题,都是由于key不存在导致的。
比如,
1.key存在,但是过期,导致某一时刻key不存在。
2.key本来就不存在。
只要key不存在,不管是什么原因导致key不存在,所有的流量都会到达数据库。数据库就会死翘翘。
分类
key过期,导致key某一时刻不存在
1.单个key过期
2.多个key同时过期
key本来就不存在
1.单个key不存在
2.多个key不存在
单个key过期
过期会导致什么问题呢?
流量高峰。即高并发。高并发导致的问题就是,数据库受不了。
本来缓存,就是为了解决数据库受不了的问题的,现在key过期了,导致流量全部跑到数据库,数据库扛不住。
解决方案
如何解决?就是读不走数据库,走缓存。现在缓存过期了,必须要走缓存,怎么办?核心还是不让流量到数据库。
这个不让,不是说一个都不让,而是同一时刻,只能有一个流量请求数据库。其他流量,都不能请求数据库。
这个是核心思路。
代码
public String get(key) {
String value = redis.get(key);
if (value == null) { //代表缓存值过期
//设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db
if (redis.setnx(key_mutex, 1, 3 * 60) == 1) { //代表设置成功
value = db.get(key);
redis.set(key, value, expire_secs);
redis.del(key_mutex);
return value;
} else { //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
sleep(50);
get(key); //重试
}
} else { //数据存在,直接返回
return value;
}
}
说明
基于redis分布式锁,确保同一时刻,只有一个流量请求数据库。
多个key同时过期
什么情况下会导致多个key同时过期?
1.设置的时候,多个key的过期时间一样
2.缓存服务器重启,比如memcache
怎么解决?
让不同的key,过期时间不一样。比如,过期时间后面再加一个时间的随机数。
概念
这里要解决的问题,其实就是缓存雪崩的问题。
单个key本来就不存在
什么情况会导致key本来就不存在?
很有可能是被别人攻击。
解决方法?
核心思路,还要一样,就是不让流量到数据库。怎么办?还是缓存。就是key不存在,也要缓存。说白了,就是查询key的时候,value为null,这个时候1.读数据库2.写到缓存。
其实,这里的步骤,和过期的解决方法,是一模一样的。所以,解决方法和实现代码是一样的。
唯一的区别,就是过期的情况,是你的系统,本来就是需要缓存这个key的。但是现在这里的情况,是本来你的系统是不需要缓存这个key的,但是为了避免击垮数据库,才去缓存这个key的。本质的区别,就在这里。
概念
这里要讨论的问题,其实就是缓存击穿的概念。
多个key本来就不存在
背景
黑客攻击的时候,不可能只使用一个不存在的key。要攻击,也是不断的变换着使用不同的不存在的key去攻击。
解决方法
布隆管理器。主要解决海量数据集合里,校验某个数据是否在集合里。本质是基于bit的思想。
大致思路是
1.海量数据集合,保存了所有本来应该存在的key
2.每次请求的时候,校验key是否在集合里,在,就读缓存;不在,就直接返回,即不让请求访问数据库。
总结
所有的解决方案,基本的核心思路就是,不让访问数据库。即要么访问缓存,要么直接返回。
如果同一时刻,高并发,那么也只能有一个请求访问数据库。其他线程,要么重试,要么直接返回。
参考
cloud.tencent.com/developer/a… www.iteye.com/blog/carlos…
tech.meituan.com/2016/12/02/… juejin.cn/post/684490…