1 Star 0 Fork 176

pinuohan / Java-learning

forked from 程序员大彬 / Java-learning 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
缓存穿透、缓存雪崩、缓存击穿.md 3.34 KB
一键复制 编辑 原始数据 按行查看 历史
Tysondai 提交于 2021-09-11 16:20 . update

Table of Contents generated with DocToc

缓存穿透

缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,如果从DB查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到DB去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了。

  1. 缓存空值,不会查数据库
  2. 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,查询不存在的数据会被这个bitmap拦截掉,从而避免了对DB的查询压力。

布隆可以看成数据库的缩略版,用来判定是否存在值。启动的时候过滤器是要全表扫描的,数据库数据发生变化的时候会更新布隆过滤器。

布隆过滤器的原理:当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。查询时,将元素通过散列函数映射之后会得到k个点,如果这些点有任何一个0,则被检元素一定不在,直接返回;如果都是1,则查询元素很可能存在,就会去查询redis和数据库。

图片来源网络

缓存雪崩

缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重挂掉。

解决方法:在原有的失效时间基础上增加一个随机值,使得过期时间分散一些。

缓存击穿

缓存击穿:大量的请求同时查询一个 key 时,此时这个key正好失效了,就会导致大量的请求都落到数据库。缓存击穿是查询缓存中失效的 key,而缓存穿透是查询不存在的 key。

解决方法:加互斥锁(redis分布式锁或者使用ReentrantLock),第一个请求的线程可以拿到锁,拿到锁的线程查询到了数据之后设置缓存,其他的线程获取锁失败会等待50ms然后重新到缓存取数据,这样便可以避免大量的请求落到数据库。

public String get(key) {
      String value = redis.get(key);
      if (value == null) { //代表缓存值过期
          String key_mutex = "mutext:key:" + key;
          //设置30s的超时,防止del操作失败的时候,下次缓存过期一直不能load db
		  if (redis.set(key_mutex, 1, 'NX', 'PX', 30000) == 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;      
          }
 }

SETNX:只有不存在的时候才设置,可以利用它来实现锁的效果。

Java
1
https://gitee.com/pinuohan/Java-learning.git
git@gitee.com:pinuohan/Java-learning.git
pinuohan
Java-learning
Java-learning
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891