美文网首页
缓存穿透、缓存雪崩、缓存击穿

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

作者: 杰哥长得帅 | 来源:发表于2019-01-06 23:18 被阅读31次

缓存穿透

黑客故意去请求缓存中不存在的数据(如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询),导致所有的请求都怼到数据库上,从而数据库连接异常

解决方案

(一) 利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试

(二) 采用异步更新策略,无论 key 是否取到值,都直接返回。value 值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热操作

(三) 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法:如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟(浪费内存,且可能对业务有影响)

缓存雪崩

缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常

解决方案

(一) 给缓存的失效时间,加上一个随机值,避免集体失效

(二) 用加锁或者队列的方式控制读数据库写缓存的线程数量,比如对某个 key 只允许一个线程查询数据和写缓存,其他线程等待,但是该方案吞吐量明显下降了

(三) 双缓存。设置两个缓存,缓存 A 和缓存 B。缓存 A 的失效时间为 20 分钟,缓存 B 不设失效时间。自己做缓存预热操作:

  1. 从缓存 A 读数据库,有则直接返回
  2. A 没有数据,直接从 B 读数据,直接返回,并且异步启动一个更新线程
  3. 更新线程同时更新缓存 A 和缓存 B

缓存击穿

对于一些设置了过期时间的 key,如果这些 key 可能会在某些时间点被超高并发地访问,是一种非常 “热点” 的数据。这个时候,需要缓存被 “击穿” 的问题,这个和缓存雪崩的区别在于这里针对某一 key 缓存,前者则是很多 key

解决方案

(一) 利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试(有可能存在死锁风险:如果另外的线程获取的资源正好是当前线程锁定的资源,同时当前线程即将要去访问另外线程正锁定的内容,就出现了死锁)

(二) 提前使用互斥锁
在 value 内部设置 1 个超时值 timeout1,timeout1 比实际的超时时间 timeout2 小。当从 cache 读取到 timeout1 发现它已经过期时,马上延长 timeout1 并重新设置到cache。然后再从数据库加载数据并设置到 cache 中

(三) 分级缓存

相关文章

网友评论

      本文标题:缓存穿透、缓存雪崩、缓存击穿

      本文链接:https://www.haomeiwen.com/subject/jtosrqtx.html