1.缓存使用场景
* 什么情况适合用缓存?考虑以下两种场景:
1.短时间内相同数据重复查询多次且数据更新不频繁,这个时候可以选择先从缓存查询,查询不到再从数据库加载并回设到缓存的方式。此种场景较适合用单机缓存。
2.高并发查询热点数据,后端数据库不堪重负,可以用缓存来扛。
*
* reference :
* optimization of cache http://tech.meituan.com/performance_tunning.html
* performance optimization http://tech.meituan.com/performance_tunning.html
* http://tech.meituan.com/performance_tuning_pattern.html
* cache overload http://tech.meituan.com/avalanche-study.html
*
* 什么情况适合用缓存?考虑以下两种场景:
1.短时间内相同数据重复查询多次且数据更新不频繁,这个时候可以选择先从缓存查询,查询不到再从数据库加载并回设到缓存的方式。此种场景较适合用单机缓存。
2.高并发查询热点数据,后端数据库不堪重负,可以用缓存来扛。
*
* reference :
* optimization of cache http://tech.meituan.com/performance_tunning.html
* performance optimization http://tech.meituan.com/performance_tunning.html
* http://tech.meituan.com/performance_tuning_pattern.html
* cache overload http://tech.meituan.com/avalanche-study.html
*
*/
2.缓存击穿问题
缓存被“击穿”问题
对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑另外一个问题:缓存被“击穿”的问题。
- 概念:缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
-
如何解决:业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。类似下面的代码:
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; } }