26 | 缓存异常(下):如何解决缓存雪崩、击穿、穿透难题?
蒋德钧
该思维导图由 AI 生成,仅供参考
你好,我是蒋德钧。
上节课,我们学习了缓存和数据库的数据不一致问题和应对方法。除了数据不一致问题,我们常常还会面临缓存异常的三个问题,分别是缓存雪崩、缓存击穿和缓存穿透。这三个问题一旦发生,会导致大量的请求积压到数据库层。如果请求的并发量很大,就会导致数据库宕机或是故障,这就是很严重的生产事故了。
这节课,我就来和你聊聊这三个问题的表现、诱发原因以及解决方法。俗话说,知己知彼,百战不殆。了解了问题的成因,我们就能够在应用 Redis 缓存时,进行合理的缓存设置,以及相应的业务应用前端设置,提前做好准备。
接下来,我们就先看下缓存雪崩的问题和应对方案。
缓存雪崩
缓存雪崩是指大量的应用请求无法在 Redis 缓存中进行处理,紧接着,应用将大量请求发送到数据库层,导致数据库层的压力激增。
缓存雪崩一般是由两个原因导致的,应对方案也有所不同,我们一个个来看。
第一个原因是:缓存中有大量数据同时过期,导致大量请求无法得到处理。
具体来说,当数据保存在缓存中,并且设置了过期时间时,如果在某一个时刻,大量数据同时过期,此时,应用再访问这些数据的话,就会发生缓存缺失。紧接着,应用就会把请求发送给数据库,从数据库中读取数据。如果应用的并发请求量很大,那么数据库的压力也就很大,这会进一步影响到数据库的其他正常业务请求处理。我们来看一个简单的例子,如下图所示:
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文详细介绍了缓存异常问题中的缓存雪崩、缓存击穿和缓存穿透,以及针对这些问题的诱发原因和解决方法。针对缓存雪崩问题,文章提出了避免给大量数据设置相同过期时间、服务降级和请求限流等解决方案。对于缓存击穿问题,建议不设置过期时间以应对访问频繁的热点数据。针对缓存穿透问题,提出了缓存空值或缺省值、使用布隆过滤器和在请求入口的前端进行请求检测等解决方法。文章通过具体案例和图示,详细阐述了每个问题的应对方案,为读者提供了解决缓存异常问题的实用指南。同时,强调了预防式方案的重要性,建议尽量避免使用“有损”方案,如服务熔断、服务降级和请求限流。整体而言,本文内容丰富,提供了全面的解决方案,对读者解决缓存异常问题具有指导意义。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Redis 核心技术与实战》,新⼈⾸单¥68
《Redis 核心技术与实战》,新⼈⾸单¥68
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(51)
- 最新
- 精选
- 徐培我觉得并没有必要:采用服务熔断、服务降级、请求限流的方法来应对缓存穿透的场景; 因为缓存穿透的场景实质上是因为查询到了Redis和数据库中没有的数据。 熔断、降级、限流,本质上是为了解决Redis实例没有起到缓存层作用这种情况;在损失业务吞吐量的代价下,在时间的作用下,随着过期key慢慢填充,Redis实例可以自行恢复缓存层作用。 而缓存穿透的场景,是因为用户要让Redis和数据库提供一个它没有的东西。这种场景下,如果没有人工介入,不论时间过去多久,都不太可能会自然恢复。 采用这种有损业务吞吐量的行为,会拖慢系统响应、降低用户体验、给公司一种系统“勉强能用”的错觉;但对问题的解决没有帮助。 最好的办法是事前拦截,降低这种类型的请求打到系统上的可能。布隆过滤器虽然判别数据存在可能有误判的情况,但判别数据不存在不会误判。可以降低数据库无效的访问。
作者回复: 回答的非常好!看到了缓存穿透的本质,也看清了和击穿、雪崩情况的区别。
2020-10-1810156 - walle斌1)、缓存雪崩还有一个场景,是一致性hash环的集群特性导致的。集群中 某个主从节点挂掉了,请求分散到其他集群,但是量极大,把其他集群也都冲垮了。 解决办法,如果场景是热的极热 冷的极冷,不建议使用 一致性hash环的集群玩法,直接使用逻辑分组,挂掉的就暂时挂掉,后续人工恢复。 总比打垮整个系统的好 2)、缓存击穿 不只有不写过期时间,也可以对读数据做预判,例如主动给某些热的数据做 过期时间延期操作。 3)、布隆过滤器介绍 最后一部分 关于命中这部分缺少了,如果都是1 那么结果返回 存在,但是真正存在吗? 不一定,可能是由于其他value的hash函数填充的,所以 对于 布隆过滤器 返回存在的,我们要穿透到缓存与db中查询。 像一个极端情况,如果 整个bit数组 都是1 或者大部分都是1的场景,这说明什么? 说明布隆过期已经基本被填满了,也说明超出了布隆过滤器 一开始预期的大小,没错 布隆过滤器是需要事先预知 总容量大小与误判率预期的,否则就会出现 误判率极高 基本等于 没有作用的情况
作者回复: 很赞的内容补充!谢谢。
2020-12-24558 - cpzhao关于穿透和雪崩,可以理解为数据的缓存命中率的不同程度的表现。雪崩代表此时命中率很低或者为0,已经到了影响DB的程度了。 同理,发生了缓存穿透,我觉得要看穿透的严重程度,可以统计命中率,在db还能抗住的情况下,可以不用熔断、降级、和限流,否则影响体验。假设命中率已经到了极限值,那这时候穿透问题上升为雪崩级别了,则可以按需要选择熔断、降级或者限流等策略
作者回复: 穿透很多时候还是指较少的数据需要到后端DB查询,如果DB还能撑住,采取的措施可以少些。雪崩就像这个名字一样,影响范围很大了,大量的数据都失效了,都要到后端DB去查询了,会给DB带来很大压力。
2020-12-076 - Andrew.Fang布隆过滤器怎么用你,Redis有没有命令
作者回复: Redis的布隆过滤器是通过module进行安装的,可以下载module源码编译,然后通过下面启动方式加载这个功能 redis-server --loadmodule ./redisbloom.so 加载module后,可以用BF.ADD加入数据,BF.EXISTS判断数据是否存在。 可以参考这个链接 https://oss.redislabs.com/redisbloom/
2020-12-192 - Kaito是否可以采用服务熔断、服务降级、请求限流的方法来应对缓存穿透问题? 我觉得需要区分场景来看。 如果缓存穿透的原因是恶意攻击,攻击者故意访问数据库中不存在的数据。这种情况可以先使用服务熔断、服务降级、请求限流的方式,对缓存和数据库层增加保护,防止大量恶意请求把缓存和数据库压垮。在这期间可以对攻击者进行防护,例如封禁IP等操作。 如果缓存穿透的原因是,业务层误操作把数据从缓存和数据库都删除了,如果误删除的数据很少,不会导致大量请求压到数据库的情况,那么快速恢复误删的数据就好了,不需要使用服务熔断、服务降级、请求限流。如果误操作删除的数据范围比较广,导致大量请求压到数据库层,此时使用服务熔断、服务降级、请求限流的方法来应对是有帮助的,使用这些方法先把缓存和数据库保护起来,然后使用备份库快速恢复数据,在数据恢复期间,这些保护方法可以为数据库恢复提供保障。 还有一种缓存穿透的场景,我们平时会遇到的,和大家分享一下。 对于一个刚上线的新业务模块,如果还没有用户在这个模块内产生业务数据,当用户需要查询这个业务模块自己的数据时,由于缓存和数据库都没有这个用户的数据,此时也会产生缓存穿透,但这种场景不像误删数据和恶意攻击那样,而是属于正常的用户行为。 这种场景采用服务熔断、服务降级、请求限流的方式就没有任何意义了,反而会影响正常用户的访问。这种场景只能使用缓存回种空值、布隆过滤器来解决。 可见,服务熔断、服务降级、请求限流的作用是,当系统内部发生故障或潜在问题时,为了防止系统内部的问题进一步恶化,所以会采用这些方式对系统增加保护,待系统内部故障恢复后,可以依旧继续对外提供服务,这些方法属于服务治理的范畴,在任何可能导致系统故障的场景下,都可以选择性配合使用。 另外,关于文章所讲的由于“Redis缓存实例发生故障宕机”导致缓存雪崩的问题,我觉得一个可以优化的方案是,当Redis实例故障宕机后,业务请求可以直接返回错误,没必要再去请求数据库了,这样就不会导致数据库层压力变大。当然,最好的方式还是Redis部署主从集群+哨兵,主节点宕机后,哨兵可以及时把从节点提升为主,继续提供服务。 关于布隆过滤器的使用,还有几点和大家分享。 1、布隆过滤器会有误判:由于采用固定bit的数组,使用多个哈希函数映射到多个bit上,有可能会导致两个不同的值都映射到相同的一组bit上。虽然有误判,但对于业务没有影响,无非就是还存在一些穿透而已,但整体上已经过滤了大多数无效穿透请求。 2、布隆过滤器误判率和空间使用的计算:误判本质是因为哈希冲突,降低误判的方法是增加哈希函数 + 扩大整个bit数组的长度,但增加哈希函数意味着影响性能,扩大数组长度意味着空间占用变大,所以使用布隆过滤器,需要在误判率和性能、空间作一个平衡,具体的误判率是有一个计算公式可以推导出来的(比较复杂)。但我们在使用开源的布隆过滤器时比较简单,通常会提供2个参数:预估存入的数据量大小、要求的误判率,输入这些参数后,布隆过滤器会有自动计算出最佳的哈希函数数量和数组占用的空间大小,直接使用即可。 3、布隆过滤器可以放在缓存和数据库的最前面:把Redis当作布隆过滤器时(4.0提供了布隆过滤器模块,4.0以下需要引入第三方库),当用户产生业务数据写入缓存和数据库后,同时也写入布隆过滤器,之后当用户访问自己的业务数据时,先检查布隆过滤器,如果过滤器不存在,就不需要查询缓存和数据库了,可以同时降低缓存和数据库的压力。 4、Redis实现的布隆过滤器bigkey问题:Redis布隆过滤器是使用String类型实现的,存储的方式是一个bigkey,建议使用时单独部署一个实例,专门存放布隆过滤器的数据,不要和业务数据混用,否则在集群环境下,数据迁移时会导致Redis阻塞问题。2020-10-1626358
- 大饶Raysir可以记录ip和穿透访问的次数,频率超过阈值的ip直接拉黑2020-10-2017
- 单小灰老师,我有个疑问,使用布隆过滤器来应对缓存穿透,那当应用刚启动的时候,布隆过滤器全是0,这样不是所有请求都会被判断为数据不存在就都直接返回了?难不成要预加载,把数据库的数据都来过滤器这边设置一遍?2020-11-03214
- 而立斋先来自己理解一下这四个问题的表现吧: 1,缓存数据与数据库数据不一致,这个就很容易理解了,就是数据出现偏差了,导致的原因是在数据变动时只更新了其中一个 2,缓存雪崩呢?缓存挂了,或者大部分key都失效了,这一下请求都打到数据库,它累了 3,缓存击穿:热点数据的失效,就像针一样同样的请求一下子刺穿了数据库的心脏 4,缓存穿透,key根本就存在无论是缓存还是数据库,但是请求一直来,这就很恶心 为什么要起 其实明白这些,一些常用的手段也就呼之欲出了。真不明白起这么多装逼的名字干嘛,不就是因为流量大了,缓存因自身限制而导致的一些现象吗?2021-04-1611
- Geek3113布隆过滤器保护的数据只能加不能删,如果用来保护的业务数据会有删除的情况怎么办呢?2020-10-2634
- test思考题:服务熔断、服务降级、请求限流,相当于减少了数据库的压力,对于缓存穿透也是可用的。 雪崩:一批次的key同一时间失效或者redis宕机,导致同一时间有大量请求打到数据库,造成数据库很大的压力。解决方案是设置key过期时间的时候加一个随机值,或者服务熔断、服务降级、请求限流等方案; 击穿:访问非常频繁的热点数据失效,解决方案是热点数据不设置过期时间; 穿透:数据库里面没有目标数据,解决方案是布隆过滤器或者前端做验证。2020-10-163
收起评论