Redis—缓存雪崩、缓存击穿、缓存穿透

1、缓存雪崩

不少时候,Redis中的缓存是要设置过时时间的,假如Redis中的数据,过时时间都设置成同样的,那么到了时间以后,所有缓存过时失效,下一秒全部的请求都会访问数据库,那么数据库可能由于访问量过大致使“崩溃”,这就是缓存雪崩。html

若是缓存集中在一段时间内失效,发生大量的缓存穿透,全部的查询都落在数据库上,形成了缓存雪崩。redis

这个没有完美解决办法,但能够分析用户行为,尽可能让失效时间点均匀分布。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。算法

应对方法:数据库

一、缓存永远不过时:最暴力的解决办法,缓存不设置自动过时时间,只要缓存不崩,数据库就不会崩。缓存

二、使用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。并发

加锁排队. 限流-- 限流算法. 1.计数 2.滑动窗口 3.  令牌桶Token Bucket 4.漏桶 leaky bucket [1]。框架

在缓存失效后,经过加锁或者队列来控制读数据库写缓存的线程数量。好比对某个key只容许一个线程查询数据和写缓存,其余线程等待。异步

三、作二级缓存,或者双缓存策略。spa

A为原始缓存,B为拷贝缓存。A失效时,能够访问B,缓存A的失效时间为20分钟,缓存B不设置失效时间。本身作缓存预热操做。细分如下几个小点:线程

  • 从缓存A读数据库,有则直接返回。
  • 若缓存A没有数据,直接从B读数据,直接返回,而且异步启动一个更新线程。
  • 更新线程同时更新缓存A和缓存B。

四、给缓存的失效时间,加上一个随机值,避免集体失效。让缓存过时时间不那么一致,好比一批缓存数据24小时后过时,那么就在这个基础上,每条缓存的过时时间先后随机1-6000秒(1-10分钟)。设置不一样的过时时间,让缓存失效的时间点尽可能均匀。

2、缓存击穿

缓存击穿跟缓存雪崩有点像,可是又有一点不同,缓存雪崩是由于大面积的缓存失效,打崩了DB,而缓存击穿不一样的是缓存击穿是指一个Key很是热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个无缺无损的桶上凿开了一个洞。

应对方法:

一、设置热点数据永远不过时。或者加上互斥锁就能搞定了。

https://www.lizenghai.com/archives/27853.html

https://mp.weixin.qq.com/s?__biz=MzUxNDA1NDI3OA==&mid=2247484581&idx=2&sn=54f2306012619e3dbe36c4fcf9493039&chksm=f94a854cce3d0c5a8be0825de18d381b388d247a7a2145759c3818cfcfa28a364bf8b8b38383&mpshare=1&scene=23&srcid=0627JwWmdlo4tdChETfgpSBL#rd

3、缓存穿透

不少项目在使用Redis或其余缓存框架的时候,都是先查询缓存,查询不到的话再查询数据库,查到以后再放到缓存(内存)中;若是一个key值自己就不存在,那么每一次都会查询数据库,也就是常说的【缓存穿透】。简单理解就是先去缓存中找不到,再去数据库查询,在数据库中也找不到,就发生了缓存穿透。

key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。好比用一个不存在的用户id获取用户信息,不论缓存仍是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。

缓存穿透是指查询一个必定不存在的数据,因为缓存是不命中时须要从数据库查询,查不到数据则不写入缓存,这将致使这个不存在的数据每次请求都要到数据库去查询,形成缓存穿透。数据在redis不存在,数据库也不存在,返回空,通常来讲空值是不会写入redis的,若是反复请求同一条数据,那么则会发生【缓存穿透】。

应对方法:

一、缓存空对象

若是在Redis中查询不到,而且查询数据库也没有结果,那么就将这个key设置一个空值(value=空),同时写入到Redis中,并设置一个超时过时时间,例如五分钟,那么五分钟之内对这个key的全部查询就能够拦截下来,就不会访问数据库了。若是数据库有key对应的数据了,那么五分钟后Redis中的缓存过时,会访问数据库并加载缓存;可是若是被恶意攻击,每次请求的key都不相同且在数据库中也是不存在的,那么依然会发生缓存穿透,会穿透到数据库。

 若是一个数据库查询返回的数据为空,咱们仍然把这个空结果进行缓存,但它的过时时间会很短,最长不超过五分钟。缓存空对象会有两个问题:

  • 空值作了缓存,意味着缓存层中存了更多的键,须要更多的内存空间 ( 若是是攻击,问题更严重 ),比较有效的方法是针对这类数据设置一个较短的过时时间,让其自动剔除。
  • 缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有必定影响。例如过时时间设置为 5分钟,若是此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时能够利用消息系统或者其余方式清除掉缓存层中的空对象。

二、布隆过滤器

将可能存在的数据Hash到一个足够大的bitmap上,它能够告诉你 “某个key必定不存在或者可能存在”,一个必定不存在的数据会被bitmap拦截。

4、缓存并发

大多数时候,咱们的程序访问Redis都不多是单线程,那么当多个Client并发对Redis进行set key操做的时候,可能会产生一些问题;其实Redis自己是单线程的,这种时候会按照前后顺序进行操做;或者把操做放在队列中,按顺序执行;

但好比这种状况:

1.token过时,有两个线程都去从新获取token;

2.线程1获取到token1;

3.线程2获取到token2,此时token1过时;

4.线程1把token1放到Redis,再拿着token1去调用服务,发现过时了,继续去请求token3,此时token2过时;

5.线程2把token2放到Redis,再拿着token2去调用服务,发现过时了,继续去请求token4,此时token3过时;

6.... ...

这就须要咱们在更新缓存的时候,作一些控制了。

相关文章
相关标签/搜索