当缓存里的热点数据过期或者被删除后,大量的请求同时访问数据库,导致数据库服务器宕机。业界的解决方案的使用 mutex。
何谓 mutex?
互斥锁(英语:Mutual exclusion,缩写 Mutex)是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制。
A Mutex is a mutually exclusive flag. It acts as a gate keeper to a section of code allowing one thread in and blocking access to all others. This ensures that the code being controled will only be hit by a single thread at a time. Just be sure to release the mutex when you are done. :)
在缓存过期后,先判空,不立即去 load db,而是使用缓存工具的某些带成功操作的(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,设置成功了再去load db ,设置缓存,否则重试整个获取缓存的方法。SETNX,是「SET if Not Exists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。
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;
}
}