Foreword
Design a caching system, problems do not consider is: Cache penetrate, and when the avalanche breakdown cache failure.
Cache penetration
Cache penetration refers to a certain query data does not exist, because the cache is not passive when writing a hit, and for fault-tolerant considerations, finding out if the data is not written to the cache from the storage layer, which will lead to the non-existent each time a data request should go to the storage layer to make inquiries, it lost the meaning of the cache. When large flow, DB may hang, if someone take advantage of the absence of key frequently attack our application this is the loophole
solution
Option One: Bloom filter, all possible data hash to a sufficiently large bitmap in a certain data does not exist this bitmap will be blocked off, thus avoiding queries pressure on the underlying storage system
Option Two: If a query returned an empty data (whether data does not exist, or system failure), then we let this empty cache results, but his expiration time will be very short, the longest no more than 5 minutes
Cache avalanche
Avalanche buffer means using the same expiration time when we set the cache, cause the cache to be invalidated at a time, the request is forwarded to all of DB, DB instantaneous pressure cause excessive avalanche
solution
Expiration time cached data set randomly, the same time to prevent the phenomenon of large amounts of data expired
If the cache database is distributed deployment, the hotspot data is evenly distributed in different cache database, dispersing pressure
Set hot data never expires
Cache breakdown
It refers to the breakdown cache data in the cache, but there is no data in the database (typically the buffer time expires), then more complicated due to the particular user, while the data read is not a read cache, and database to fetch data while causing the database instant pressure increase, resulting in excessive pressure
solution
Set hot data never expires
Use mutex
public String get(key){
//缓存中读取数据
String value = redis.get(key);
//缓存中不存在
if(value == null){//代表缓存之过期
//加锁 设置3分钟的超时,防止del操作失败的时候,下次缓存过期一直不能load 数据库
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);
//重新尝试获取缓存
value = redis.get(key);
}
}
return value;
}