目录
一、什么是缓存击穿、缓存穿透、缓存雪崩?
缓存击穿:是指当某一个key的缓存过期时,大并发量的请求同时访问此key,瞬间击穿缓存服务器直接访问数据库,让数据库处于负载的情况。
缓存穿透:缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,我们数据库的 id 都是1开始自增上去的,如发起为id值为 -1 的数据或 id 为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大,严重会击垮数据库。
缓存雪崩:是当大量缓存同时过期或缓存服务宕机,所有请求的都直接访问数据库,造成数据库高负载,影响性能,甚至数据库宕机。
在记忆这几个概念的时候,不要死记硬背,你可以尝试这样记忆:
首先,雪崩的概念比较容易记,就是很多个Key同时过期才会雪崩,“缓存雪崩的时候没有一个Key是无辜的”。至于穿透和击穿,区别在于穿透是“透”,什么叫透呢,那就是不仅缓存被击穿了,数据库也被击穿了,这种才叫透。所以,这种缓存和数据库中都没有的情况叫做“缓存穿透”。
二、解决方法
2.1 缓存击穿
异步定时更新
比如某一个热点数据的过期时间是1小时,那么每59分钟,通过定时任务去更新这个热点key,并重新设置其过期时间。
互斥锁
在缓存处理上,通常使用一个互斥锁来解决缓存击穿的问题。简单来说就是当Redis中根据key获得的value值为空时,先锁上,然后从数据库加载,加载完毕,释放锁。若其他线程也在请求该key时,发现获取锁失败,则先阻塞。
2.2 缓存穿透
缓存空值
在缓存中,之所以会发生穿透,就是因为缓存没有对那些不存在的值得Key缓存下来,从而导致每次查询都要请求到数据库。
那么我们就可以为这些key对应的值设置为null并放到缓存中,这样再出现查询这个key 的请求的时候,直接返回 null即可。
但是还需要注意的就是需要有一个失效时间,因为如果不设置失效的话,如果哪天总部有货了,门店还是当做没货的话,就会影響销量了。
布隆过滤器 BloomFilter
很多时候,缓存穿透是因为有很多恶意流量的请求,这些请求可能随机生成很多Key来请求查询,这些肯定在缓存和数据库中都没有,那就很容易导致缓存穿透。
针对类似的情况,可以使用一个过滤器。
在缓存穿透防治上常用的技术是布隆过滤器(Bloom Filter)。
布隆过滤器是一种比较巧妙的概率性数据结构,它可以告诉你数据一定不存在或可能存在,相比Map、Set、List等传统数据结构它占用内存少、结构更高效。
对于缓存穿透,我们可以将查询的数据条件都哈希到一个足够大的布隆过滤器中,用户发送的请求会先被布隆过滤器拦截,一定不存在的数据就直接拦截返回了,从而避免下一步对数据库的压力。
2.3 缓存雪崩
设置不同的过期时间
为了避免大量的缓存在同一时间过期,可以把不同的key过期时间设置成不同的,并且通过定时刷新的方式更新过期时间。
把每个Key的失效时间都加个随机值就好了。
setRedis(Key,value,time + Math.random() * 10000);
集群
如果Redis是集群部署,将热点数据均匀分布在不同的Redis库中也能避免全部失效的问题。
热点数据永不过期
设置热点数据永远不过期,有更新操作就更新缓存就好了(比如运维更新了首页商品,那你刷下缓存就完事了,不要设置过期时间)。