如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,就造成了缓存雪崩。
缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。
如何解决缓存穿透
缓存击穿
在平常高并发的系统中,大量的请求同时查询一个 key 时,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去。这种现象我们称为缓存击穿。
如何解决缓存击穿
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; } }
缓存和数据库都是分别更新的,我们没有办法保证这2个始终是一致的。但是我们可以追求最终一致。现在普遍的策略就是不要更新缓存,我们先删除缓存,然后更新数据库,可能发生的是删除缓存和更新数据库之间又有数据读缓存,这个时候可以采用延迟双删。
(1)先淘汰缓存
(2)再写数据库(这两步和原来一样)
(3)休眠x秒,再次淘汰缓存
这么做,可以将x秒内所造成的缓存脏数据,再次删除。x的时间与自己业务的时间相符。
欢迎关注公众号蜜蜂技术巢了解更多知识