缓存穿透
缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也
不会有。这样就导致用户查询的时候,在缓存中找不到,每次
都要去数据库再查询一遍,然后返回空(相当于进行了两次无
用的查询)。这样请求就绕过缓存直接查数据库,这也是经常
提的缓存命中率问题。
解决
对空值缓存
:如果一个查询返回的数据为空(不管数据是否存在),我们仍然把这个空结果缓存,
设置空结果的过期时间会很短,最长不超过
5
分钟。
1
布隆过滤器
:如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起
来,然后通过比较确定。
代码:
/** * 布隆过滤器,,解决缓存穿透 */ @Test public void filter(){ BitMapBloomFilter bitMapBloomFilter = new BitMapBloomFilter(10); bitMapBloomFilter.add("ads"); bitMapBloomFilter.add("abc"); bitMapBloomFilter.add("123"); bitMapBloomFilter.add("456"); System.out.println(bitMapBloomFilter.contains("dfgdf")); System.out.println(bitMapBloomFilter.contains("abc")); System.out.println(bitMapBloomFilter.contains("a")); }
缓存击穿
某一个热点
key
,在缓存过期的一瞬间,同时有大量的请求打进
来,由于此时缓存过期了,所以请求最终都会走到数据库,造成瞬
时数据库请求量大、压力骤增,甚至可能打垮数据库。(某个key失效时,有多个请求访问)
解决
互斥锁
:在并发的多个请求中,只有第一个请求线程能拿到锁并执行数据库查询操作,其他的线程
拿不到锁就阻塞等着,等到第一个线程将数据写入缓存后,其他线程直接查询缓存。
1
热点数据不过期
:直接将缓存设置为不过期,然后由定时任务去异步加载数据,更新缓存。
代码
/** * 互斥锁,,解决缓存缓存击穿 */ @Test public void lock(String key) throws InterruptedException { Jedis jedis = new Jedis("192.168.66.100", 6379); String value = jedis.get("key"); if (value == null){ //只有在key不存在时才创建 long setnx = jedis.setnx(key + "_hc", "1"); //设置过期时间 jedis.pexpire(key + "_hc",3*60); //设置成功 if (setnx == 1){ //db操作 value="db"; //保存缓存 jedis.setex(key,3*60,value); //删除 jedis.del(key+"_hc"); }else { Thread.sleep(5000); lock(key); } } }
缓存雪崩
缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存
在某一时刻同时失效,请求全部转发到
DB
,
DB
瞬时压力过重雪
崩。(多个key同一时间失效)
解决
过期时间打散
:既然是大量缓存集中失效,那最容易想到就是让他们不集中生效。可以给缓存的过
期时间时加上一个随机值时间,使得每个
key
的过期时间分布开来,不会集中在同一时刻失效。
热点数据不过期
:该方式和缓存击穿一样,也是要着重考虑刷新的时间间隔和数据异常如何处理的
情况。
加互斥锁
:
该方式和缓存击穿一样,按
key
维度加锁,对于同一个
key
,只允许一个线程去计算,
其他线程原地阻塞等待第一个线程的计算结果,然后直接走缓存即可。
代码
/** * 加锁,解决缓存雪崩 */ @Test public Object saveLock(String key) { Jedis jedis = new Jedis("192.168.66.100", 6379); String lockKey = key; String value = jedis.get(key); if (value == null) { // 加锁,只允许一个线程执行 synchronized (lockKey) { String s = jedis.get(key); if (s == null) { return s; } else { // 执行查询数据库的值 value = "db"; jedis.set(key, value); return value; } } }else{ return value; } }