掘金 后端 ( ) • 2024-04-04 10:59

大家好,我是石头~

在当今的高并发互联网环境中,缓存已经成为提升系统性能的重要手段之一。

然而,就像任何利器都有其双刃性一样,我们在享受缓存带来高效的同时,也必须面对“缓存击穿”、“缓存穿透”以及“缓存雪崩”这三大挑战。

那么,这些现象究竟是怎么回事?又该如何应对呢?今天,我们就一起深入探讨这些问题。

1、正常查询流程

在研究上面三个问题之前,我们先来看下,一个正常的数据查询流程是怎样的。

image.png

如上图,在客户端发送查询请求时,服务端会先从Redis查询是否有数据,如果有,则直接返回;如果没有,则从数据库查询。数据库查询后,将结果返回给客户端,并写入到Redis中。

了解完这个基本的数据流程之后,我们就可以继续来了解下面的内容了.

2、缓存穿透

image.png

缓存穿透是指查询的数据既不存在于缓存中,也不存在于数据库中,但恶意用户或爬虫等高频访问不存在的数据,导致大量请求直接打到数据库上,形成穿透效应。

解决方案:

  • 布谷鸟过滤器预判:对所有可能存在的数据哈希,存储在布谷鸟过滤器中,当查询请求到来时,先经过布谷鸟过滤器判断,如果确定数据一定不存在,则直接返回,避免无效请求穿透到数据库。

1.布谷鸟过滤器,由于其挤兑特性,如果数组较小的话,会发生循环挤兑的情况,这个时候可以设置最大挤兑次数,如果超过该次数,进行扩容,重新计算每个指纹的位置。
2.布谷鸟过滤器存在误判可能,布谷鸟过滤器校验通过的,可能是存在,也是不存在的。而布谷鸟过滤器校验不通过的,肯定是不存在的。因此,此处在进行存在校验的时候,要校验不存在。

  • 空值缓存:即使查询结果为空,也将空值进行缓存,并设置较短的有效期,防止恶意攻击。

3、缓存击穿

image.png        缓存击穿是指热点数据过期后,在高并发场景下,大量请求同时查询数据库,导致数据库压力剧增的现象。

形象地说,就像是众多请求一同击穿了原本由缓存构筑起来的防护墙,直指后端数据库。

解决方案:

  • 互斥锁或分布式锁:在缓存失效时,通过锁,确保同时只有一个请求去查询数据库并回填缓存。

采用互斥锁虽然能有效防止缓存击穿,但在高并发场景下可能会导致请求排队等待,从而影响接口响应速度,降低系统吞吐量。
因此,对于读多写少的场景,可以使用可重入读写锁。当缓存失效时,持有写锁的线程负责从数据库加载数据并回填缓存,期间其他读请求仍可以通过读锁获取缓存中的旧数据,直至新数据加载完毕。

  • 设置热点数据永不过期,通过后台定时更新策略来保证数据新鲜度。

  • 异步更新缓存:当检测到缓存失效时,不立即阻塞请求,而是异步地将数据库加载任务放入任务队列,主线程快速返回临时默认值或旧缓存值,后续请求在数据更新完成后获取最新数据。

4、缓存雪崩

image.png

缓存雪崩是指缓存服务集体宕机或者大面积缓存同一时间失效,所有请求都涌向数据库,造成数据库瞬间压力过大甚至崩溃的情况。

解决方案:

  • 缓存预热:在缓存重启或大规模更新前,提前将数据加载到缓存中,减少瞬时流量冲击。

  • 分布式缓存集群:使用多节点部署,增加缓存系统的可用性和容错性。

  • 限流降级:在系统入口处设置合理的流量控制,如熔断机制、令牌桶算法等,当请求量超过阈值时,可以暂时拒绝部分请求或者调用降级逻辑。

5、总结

总的来说,应对缓存击穿、穿透和雪崩的问题需要综合考虑业务特性和系统负载情况,灵活应用各种策略。

这些解决方案不仅有助于维护数据库安全,也有利于提升系统的稳定性和用户体验。期待你在评论区分享你的实战经验和观点!

**MORE | 更多精彩文章**