本质
缓存击穿问题的本质是,高并发问题。
是什么?
所谓缓存击穿,就是缓存没有拦截住请求。最终走到了数据库。
为什么会这样?应用场景?
一般是流量很高的时候,这是第一。//因为流量很低,就算击穿缓存,直接访问数据库,也没啥。数据库能抗住。
另外,第二点,就是缓存没有拦截住流量。为什么没有拦截住?这个问题才是本质,要好好思考这个问题。
这个问题的本质是,什么时候,缓存会没有拦截请求?只有一个情况,那就是缓存没有数据,即读数据的时候,数据不存在,那么就去读数据库。
那么,为什么缓存没有数据?
举一个场景,缓存刚刚失效的那一刻,突然流量很高,这个时候就满足了上述的两个条件 1.流量很高 2.缓存没有数据 //因为数据到期
那这个时候,怎么解决?怎么解决这个问题?
解决方法
首先,我们来看一下,我们的最终目标是什么?就是不让高并发流量读数据库。
怎么做到?还是得用锁。单机就是使用同步关键字或显式锁。分布式服务,就是使用分布式锁。
分布式锁
不会影响速度吗?因为刚才的那种情况,是特殊场景,不会一直是那种情况。
所以,为了那片刻的短暂场景,是可以使用分布式锁的。
具体怎么使用?
代码
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);
} else { //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
sleep(50);
get(key); //重试
}
} else {
return value;
}
}
注意,锁的使用,只在过期的代码里,才使用。只有这样,才不会影响正常情况下的高并发访问。