Redis雪崩效应以及解决方案

本文探讨了缓存雪崩现象,即缓存失效导致大量请求直接冲击数据库,介绍了加锁、队列控制、二级缓存等解决方案,以及均匀分配缓存失效时间的策略。

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

Redis雪崩效应以及解决方案

缓存雪崩产生的原因

 

缓存雪崩通俗简单的理解就是:由于原有缓存失效(或者数据未加载到缓存中),新缓存未到期间(缓存正常从Redis中获取,如下图)所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机,造成系统的崩溃。

 

缓存失效的时候如下图:

 

缓存失效时的雪崩效应对底层系统的冲击非常可怕!那有什么办法来解决这个问题呢?基本解决思路如下:

  第一,大多数系统设计者考虑用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,避免缓存失效时对数据库造成太大的压力,虽然能够在一定的程度上缓解了数据库的压力但是与此同时又降低了系统的吞吐量。

 第二,分析用户的行为,尽量让缓存失效的时间均匀分布。

 第三,如果是因为某台缓存服务器宕机,可以考虑做主备,比如:redis主备,但是双缓存涉及到更新事务的问题,update可能读到脏数据,需要好好解决。

 

解决方案

1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

  缓存失效时的雪崩效应对底层系统的冲击非常可怕!那有什么办法来解决这个问题呢?基本解决思路如下:

 第一,大多数系统设计者考虑用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,避免缓存失效时对数据库造成太大的压力,虽然能够在一定的程度上缓解了数据库的压力但是与此同时又降低了系统的吞吐量。

 第二,分析用户的行为,尽量让缓存失效的时间均匀分布。

第三,如果是因为某台缓存服务器宕机,可以考虑做主备,比如:redis主备,但是双缓存涉及到更新事务的问题,update可能读到脏数据,需要好好解决。

 

 

解决方案

 

1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

     注意:加锁排队只是为了减轻数据库的压力,并没有提高系统吞吐量。假设在高并发下,缓存重建期间key是锁着的,这是过来1000个请求999个都在阻塞的。同样会导致用户等待超时,这是个治标不治本的方法。

2:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

3:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期(此点为补充)

 

架构如下所示时候:

如何攻击redis?

如果再redis中有1000个key,如果同一时间失效?   直接查数据库了 不再走redis了 ! 大连查询请求过来,,,,产生了雪崩效应~

这时候使用 限流 服务降级、熔断 的方案  这三个方案是针对redis的上一层的

 

Redis雪崩效应的解决方案

1、可以使用分布式锁   单机版的话本地锁

2、消息中间件方式

3、一级和二级缓存 Redis+Ehchache

4、均摊分配Redis的key的失效时间

 

解释:

 1、  当突然有大量请求到数据库服务器时候,进行请求限制。使用所的机制,保证只有一个线程(请求)操作。否则进行排队等待(集群分布式锁,单机本地锁)。减少服务器吞吐量,效率低。

 

 加入锁!

 

保证只能有一个线程进入  实际上只能有一个请求在执行查询操作

也可以在此处进行使用限流的策略~

 

2、使用消息中间件解决

  这种方案是最靠谱的方案!

   消息中间件 可以解决高并发!!!

  如果大量的请求进行访问时候,Redis没有值的情况,会将查询的结果存放在消息中间件中(利用了MQ同步特性

   查不到时候 走MQ  

 

 3、一级二级缓存参考: https://www.cnblogs.com/toov5/p/9892910.html

 

4、均摊分配redis key的失效时间 

     不让在同一时间失效,不同key失效时间不同 哈哈

 

     

 

### Redis 雪崩问题概述 Redis 缓存雪崩问题是分布式系统中常见的一种现象,其核心原因是缓存中的大量数据同时过期或失效,导致后续请求直接访问数据库,从而使数据库承受巨大的压力甚至崩溃。这种现象通常发生在高并发场景下。 #### 原因分析 1. **批量数据过期** 当多个缓存键设置相同的过期时间时,在同一时刻这些键会集中失效。一旦这些键失效,新的请求将绕过缓存并直接查询数据库,从而引发数据库负载激增[^2]。 2. **Redis 故障宕机** 如果 Redis 实例由于某种原因(如硬件故障、网络中断等)突然不可用,则所有的读写操作都会转向数据库层,这同样会对数据库造成极大的性能负担[^4]。 3. **突发流量高峰** 即使没有明显的缓存过期问题,但如果系统遭遇突发的大规模请求量,也可能因为缓存未及时更新而导致类似的雪崩效应[^3]。 --- ### 解决方案详解 针对上述提到的各种可能触发条件,以下是几种常用的解决策略: #### 1. 设置随机化过期时间 为了避免大批量的 key 同步到期,可以在存储每条记录的时候为其分配一个带有一定范围波动的时间戳作为 TTL (Time To Live) 参数值。例如原本计划让某类资源存活一个小时,那么实际应用过程中可以将其设定为介于 50 到 70 分钟之间的一个随机数。这样即使某些特定时间段内的热点项目确实达到了生命周期终点也不会立刻引起整体性的冲击[^1]。 ```python import random def set_with_random_expiry(redis_client, key_prefix, value): base_ttl = 60 * 60 # Base expiration time of one hour in seconds. variance = int(base_ttl * 0.2) # Allow up to +/- 20% variation. ttl = random.randint(base_ttl - variance, base_ttl + variance) redis_key = f"{key_prefix}:{value}" redis_client.setex(name=redis_key, time=ttl, value=value) ``` #### 2. 使用服务降级与熔断机制 引入 Hystrix 或 Sentinel 这样的框架实现自动化的错误恢复流程和服务隔离措施。当检测到异常情况比如延迟过高或者失败比例超标之后立即启动保护模式——暂时屏蔽掉那些容易出现问题的功能模块直到恢复正常为止;与此同时还可以考虑通过预先定义好的默认返回结果快速反馈给前端用户而不是让他们长时间等待响应完成后再被告知失败消息。 #### 3. 异步加载/预热缓存 提前做好准备工作非常重要,尤其是在预期会有大规模访问之前就应该主动填充好相应的 cache 数据项。可以通过后台线程定时扫描即将超时的数据列表并将它们重新拉取下来放入内存之中待命备用状态以便随时调用无需再次经历漫长耗时的过程去检索原始源头处的信息内容。 ```bash #!/bin/bash while true; do keys=$(redis-cli --scan --pattern 'hot_item_*' | grep '^hot_item_') for key in $keys; do remaining_time=$(redis-cli ttl "$key") if [[ $remaining_time -le 30 ]]; then item_id=${key#*_} new_data=$(fetch_from_db "$item_id") # Replace with actual DB fetching logic if [ ! -z "$new_data" ]; then redis-cli setex "$key" 90 "$new_data" fi fi done sleep 60 done ``` #### 4. 提升底层架构冗余度 最后也是最根本的一点就是加强基础设施建设水平提高抗风险能力。具体做法包括但不限于增加更多的 slave 节点组成集群形式分担主节点的工作负荷减少单点依赖可能性;另外还需要定期备份重要资料防止意外丢失等情况的发生影响正常运转秩序等等。 --- ### 总结 综上所述,Redis 的缓存雪崩虽然看似棘手但实际上只要采取适当预防手段就可以有效规避此类事件带来的负面影响。关键是平时就要养成良好习惯合理规划各项参数配置并且不断优化升级现有技术栈以适应日益增长的需求变化趋势。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值