缓存穿透,缓存雪崩,缓存击穿解决方案分析

本文深入解析缓存系统中常见的问题:缓存穿透、雪崩与击穿现象,探讨其成因及对系统的影响。并提供多种解决方案,包括使用布隆过滤器、空值缓存、加锁控制、预加载缓存、设置随机过期时间等策略,以增强系统稳定性和提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自:http://blog.youkuaiyun.com/zeb_perfect/article/details/54135506
    http://blog.youkuaiyun.com/AlbertFly/article/details/75546170


缓存穿透

  缓存穿透是指 查询一个一定不存在的数据,由于缓存不命中,需要直接从数据库查询,查不到数据则不写入缓存,这将导致每次请求不存在的key都要到数据库去查询,从系统层面来看像是穿透了缓存层直接达到db,造成缓存穿透,没有了缓存层的保护。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。

解决方案:

  • 有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用bloom filter(布隆过滤器),将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层数据库的查询压力。guava中有实现BloomFilter算法。
  • 另外也有一个更为简单粗暴的方法—空值缓存,如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。这样则可以应对短时间的大量的该key攻击,设置为较短的失效时间是因为该值可能业务无关,存在意义不大,且该次的查询也未必是攻击者发起,无过久存储的必要,故可以早点失效。

缓存雪崩

  缓存雪崩是指 在设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,导致所有的查询都落在数据库上,造成了缓存雪崩。

解决方案:

  • 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待,这样每个时刻只有一个线程在执行请求,减轻了db的压力,但缺点也很明显,降低了系统的qps。
  • 可以通过缓存reload机制,预先去更新缓存,在即将发生大并发访问前手动触发加载缓存。
  • 不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
  • 做二级缓存,或者双缓存策略。A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。

缓存击穿

  对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
  例如微博有一个热门话题的功能,用户对于热门话题的搜索量往往在一些时刻会大大的高于其他话题,由于系统中对这些热点的数据缓存也存在失效时间,在热点的缓存到达失效时间时,此时可能依然会有大量的请求到达系统,没有了缓存层的保护,这些请求同样的会到达db从而可能引起故障。
  击穿与雪崩的区别即在于击穿是对于特定的热点数据来说,而雪崩是全部数据。

解决方案:

  • 做二级缓存,或者双缓存策略。对于热点数据进行二级缓存,并对于不同级别的缓存设定不同的失效时间,则请求不会直接击穿缓存层到达数据库。

  解决此问题的关键在于热点访问。由于热点可能随着时间的变化而变化,结合LRU算法能够较好的解决这个问题。
  LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。上面的算法存在较多的不合理性,在实际的应用过程中采用该算法进行了改进,例如偶然的数据影响会造成命中率较低,比如某个数据即将到达底部即将被淘汰,但由于一次的请求又放入了头部,此后再无该数据的请求,那么该数据的继续存在其实是不合理的,针对这类情况LRU-K算法拥有更好的解决措施。
  LRU-K需要多维护一个队列或者更多,用于记录所有缓存数据被访问的历史。只有当数据的访问次数达到K次的时候,才将数据放入缓存。当需要淘汰数据时,LRU-K会淘汰第K次访问时间距当前时间最大的数据。如果数据访问没有达到K次则会继续到达链表底部直至淘汰;如果该数据在队列中时访问次数达到了K次,那么它会被加入到接下来的2级链表中,按照时间顺序在2级链表中排列。接下来2级链表中的操作与上面算法相同,链表中的数据如果再次被访问则移到头部,链表满时,底部数据淘汰

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值