📫作者简介:小明java问道之路,专注于研究 Java/ Liunx内核/ C++及汇编/计算机底层原理/源码,就职于大型金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。
📫 热衷分享,喜欢原创~ 关注我会给你带来一些不一样的认知和成长。
🏆 CSDN博客专家/后端领域优质创作者/内容合伙人、InfoQ签约作者、阿里云专家/签约博主、51CTO专家 🏆
🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~
本文目录
本文导读
由于读写速度快,Redis通常被广泛用作开发中最常用的缓存方案,然而,在实际应用过程中,会出现缓存雪崩、 缓存击穿和缓存穿透等异常,本文主要分析和总结这些缓存异常和常见的处理方案。
一、Redis缓存穿透
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
缓存穿透通常发生在以下两种情况下:缓存中的数据和数据库中的数据被错误删除,导致缓存和数据库中没有数据;黑客恶意攻击并故意访问大量读取不存在数据的企业;
解决方案:
1、非法请求的限制:在接收参数时过滤业务接口中的非法值、空值、负值和空值
2、布隆过滤器:一种类似于哈希表的算法。它使用所有可能的查询条件来生成位图,该位图将用于在数据库查询之前进行过滤。如果没有,它将被直接过滤,以减轻数据库级别的压力;
3、缓存空值:一个相对简单的解决方案。在第一次查询不存在的数据后,密钥和相应的空值也被放入缓存,但设置为较短的过期时间
二、Redis缓存雪崩
缓存服务挂掉或者热点缓存失效,所有请求都去查数据库,导致数据库连接不够或者数据库处理不过来,从而导致整个系统不可用。
发生缓存雪崩主要有两个原因:
大量(热点)数据同时过期,导致本应请求缓存的数据,需要从数据库中检索;
Redis故障宕机(服务挂掉),无法处理请求,再次请求数据库。
1、 大量(热点)数据同时过期
针对大量缓存数据同时过期,常见的解决方案如下:
1.1、均匀设置过期时间
在实际设置过期时间时,应尽量避免出现大量 key 同时过期的情况。如果有,您可以通过随机、微调甚至设置来设置过期时间,以避免同一时间过期;
1.2、互斥锁
添加互斥锁,这样缓存构建就不会同时执行;当业务线程处理用户请求时,如果发现访问的数据不在Redis中,它将添加互斥锁,以确保同时只有一个请求来构建缓存(从数据库中读取数据,然后将数据更新到Redis)。构建缓存后,释放锁。请求未能获取互斥锁。要么等待锁释放并重新读取缓存,要么返回空值或默认值。
在实现互斥锁时,最好设置一个超时,否则第一个请求会获得锁,然后这个请求会被阻止,并且由于某些意外而不会释放锁。此时,其他请求无法获得锁,整个系统将不会响应。
每个时刻只有一个线程在执行请求,减轻了db的压力,但缺点也很明显,降低了系统的qps。
1.3、双 key 策略
主key 是原始缓存, 备key 是副本缓存。当主key 失败时,可以访问备份key 。主键缓存过期时间设置为短期, 备key 设置为长期(即使没有过期);它们只有不同的键,但值是相同的,这相当于创建缓存数据的副本。
当业务线程无法访问“主键”的缓存数据时,它直接返回“备用键”的缓存信息,然后在更新缓存时同时更新“主键”和“备用键”的数据。
双key 策略的优点是,当主键过期并且有大量请求获取缓存数据时,备份key 的数据会被直接返回,这样可以快速响应请求。
1.4、后台更新缓存策略
使用定时任务或者消息队列更新或删除Redis缓存。
业务线程不再负责更新缓存,缓存也不会设置有效期。相反,缓存是“永久有效的”,并且后台线程被分配来定期更新缓存。
缓存数据没有有效期,这并不意味着数据可以一直在内存中,因为当系统内存紧张时,一些缓存数据将被“消除”。在从缓存被“消除”到下一次后台常规缓存更新的这段时间内,如果业务线程未能读取缓存,那么它将返回一个空值,业务角度将认为数据丢失。
当业务刚刚上线时,我们最好提前缓冲数据,而不是等待用户访问来触发缓存构建。这称为缓存预热。后台缓存更新机制正适合于此。
2、Redis 故障宕机(服务挂掉)
2.1、服务熔断或请求限流机制
当Redis崩溃并导致缓存雪崩时,我们可以启动服务融合机制,暂停业务应用程序对缓存服务的访问,直接返回错误,不需要继续访问数据库。
请求限流机制相对温和。启用请求限流机制,仅将少量请求发送到数据库进行处理。任何更多的请求将被直接拒绝在入口处提供服务。然而,适当的处理方案取决于具体的业务情况。
2.2、构建高可靠集群
在预防级别,可以通过使用主从节点来构建高度可用的集群。也就是说,在主Redis实例挂断后,其他从数据库可以快速切换到主数据库并继续提供服务,避免了Redis宕机带来的缓存雪崩问题。
三、Redis缓存击穿
事实上,缓存击穿是缓存雪崩的一种特殊情况。缓存击穿是指缓存中没有数据,但数据库中有数据(通常缓存时间到期)。此时,由于并发用户太多,读取缓存并不能读取数据,同时又去数据库检索数据,数据库压力瞬间增加,导致压力过大。击穿和雪崩的区别在于,击穿是针对特定的热点数据,而雪崩是所有数据。
解决方案:
1、缓存设置不过期:没有过期时间,并且后台异步更新缓存,或者在热数据准备过期之前提前通知后台线程更新缓存并重置过期时间;
2、使用锁工具(分布式锁/互斥锁方案):确保只有一个业务线程同时更新缓存,并且无法获得互斥锁请求。要么等待锁释放并重新读取缓存,要么返回空值或默认值。
总结
由于读写速度快,Redis通常被广泛用作开发中最常用的缓存方案,然而,在实际应用过程中,会出现缓存雪崩、 缓存击穿和缓存穿透等异常,本文主要分析和总结这些缓存异常和常见的处理方案。
转载:https://blog.csdn.net/FMC_WBL/article/details/128377088