Redis-缓存雪崩、击穿、穿透

本文深入探讨了缓存雪崩、穿透和击穿现象,详细解释了这些概念的区别及其对数据库的影响。文章提出了多种预防措施,包括设置随机失效时间、使用布隆过滤器和设置热点数据永不过期等策略。

提到Redis我相信各位在面试,或者实际开发过程中对缓存雪崩,穿透,击穿也不陌生吧,就 算没遇到过但是你肯定听过,那三者到底有什么区别,我们又应该怎么去防止这样的情况发生 呢,我们有请下一位受害者。

面试开始

一个大腹便便,穿着格子衬衣的中年男子,拿着一个满是划痕的mac向你走来,看着快秃 顶的头发,心想着肯定是尼玛顶级架构师吧!但是我们腹有诗书气自华,虚都不虚

小伙子我看你的简历上写到了Redis,那么我们直接开门见山,直接 怼常见的几个大问题,Redis雪崩了解么?

帅气迷人的面试官您好,我了解的,目前电商首页以及热点数据都会去做缓存 ,一般缓存都 是定时任务去刷新,或者是查不到之后去更新的,定时任务刷新就有一个问题。

举个简单的例子:如果所有首页的Key失效时间都是12小时,中午12点刷新的,我零点有个秒 杀活动大量用户涌入,假设当时每秒 6000 个请求,本来缓存在可以扛住每秒 5000 个请求, 但是缓存当时所有的Key都失效了。此时 1 秒 6000 个请求全部落数据库,数据库必然扛不 住,它会报一下警,真实情况可能DBA都没反应过来就直接挂了。此时,如果没用什么特别的 方案来处理这个故障,DBA 很着急,重启数据库,但是数据库立马又被新的流量给打死了。 这就是我理解的缓存雪崩。

我刻意看了下我做过的项目感觉再吊的都不允许这么大的QPS直接打DB去,不过没慢SQL加 上分库,大表分表可能还还算能顶,但是跟用了Redis的差距还是很大

同一时间大面积失效,那一瞬间Redis跟没有一样,那这个数量级别的请求直接打到数据库几 乎是灾难性的,你想想如果打挂的是一个用户服务的库,那其他依赖他的库所有的接口几乎都 会报错,如果没做熔断等策略基本上就是瞬间挂一片的节奏,你怎么重启用户都会把你打挂, 等你能重启的时候,用户早就睡觉去了,并且对你的产品失去了信心,什么垃圾产品。

面试官摸了摸自己的头发,嗯还不错,那这种情况咋整?你都是怎么 去应对的?

 

处理缓存雪崩简单,在批量往Redis存数据的时候,把每个Key的失效时间都加个随机值就好 了,这样可以保证数据不会在同一时间大面积失效,我相信,Redis这点流量还是顶得住的。

setRedis(Key,value,time + Math.random() * 10000);

如果Redis是集群部署,将热点数据均匀分布在不同的Redis库中也能避免全部失效的问题, 不过本渣我在生产环境中操作集群的时候,单个服务都是对应的单个Redis分片,是为了方便 数据的管理,但是也同样有了可能会失效这样的弊端,失效时间随机是个好策略。

或者设置热点数据永远不过期,有更新操作就更新缓存就好了(比如运维更新了首页商品,那 你刷下缓存就完事了,不要设置过期时间),电商首页的数据也可以用这个操作,保险。

那你了解缓存穿透和击穿么,可以说说他们跟雪崩的区别么?

嗯,了解,我先说一下缓存穿透吧,缓存穿透是指缓存和数据库中都没有的数据,而用户不断 发起请求,我们数据库的 id 都是1开始自增上去的,如发起为id值为 -1 的数据或 id 为特别大 不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大,严重会击垮数据 库。

小点的单机系统,基本上用postman就能搞死,比如我自己买的阿里服务

像这种你如果不对参数做校验,数据库id都是大于0的,我一直用小于0的参数去请求你,每次 都能绕开Redis直接打到数据库,数据库也查不到,每次都这样,并发高点就容易崩掉了。

至于缓存击穿嘛,这个跟缓存雪崩有点像,但是又有一点不一样,缓存雪崩是因为大面积的缓 存失效,打崩了DB,而缓存击穿不同的是缓存击穿是指一个Key非常热点,在不停的扛着大并 发,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿破缓存, 直接请求数据库,就像在一个完好无损的桶上凿开了一个洞。

面试官露出欣慰的眼光,那他们分别怎么解决

缓存穿透我会在接口层增加校验,比如用户鉴权校验,参数做校验,不合法的参数直接代码 Return,

比如:id 做基础校验,id <=0的直接拦截等。

这里我想提的一点就是,我们在开发程序的时候都要有一颗“不信任”的心,就是不要相信任 何调用方,比如你提供了API接口出去,你有这几个参数,那我觉得作为被调用方,任何可能 的参数情况都应该被考虑到,做校验,因为你不相信调用你的人,你不知道他会传什么参数给 你。

举个简单的例子,你这个接口是分页查询的,但是你没对分页参数的大小做限制,调用的人万 一一口气查 Integer.MAX_VALUE 一次请求就要你几秒,多几个并发你不就挂了么?是公司 同事调用还好大不了发现了改掉,但是如果是黑客或者竞争对手呢?在你双十一当天就调你这 个接口会发生什么,就不用我说了吧。这是之前的Leader跟我说的,我觉得大家也都应该了 解下。

从缓存取不到的数据,在数据库中也没有取到,这时也可以将对应Key的Value对写为null、位 置错误、稍后重试这样的值具体取啥问产品,或者看具体的场景,缓存有效时间可以设置短 点,如30秒(设置太长会导致正常情况也没法使用)。

这样可以防止攻击用户反复用同一个id暴力攻击,但是我们要知道正常用户是不会在单秒内发 起这么多次请求的,那网关层Nginx本渣我也记得有配置项,可以让运维大大对单个IP每秒访 问次数超出阈值的IP都拉黑。

那你还有别的办法么?

还有我记得Redis还有一个高级用法布隆过滤器(Bloom Filter)这个也能很好的防止缓存穿 透的发生,他的原理也很简单就是利用高效的数据结构和算法快速判断出你这个Key是否在数 据库中存在,不存在你return就好了,存在你就去查了DB刷新KV再return。

那又有小伙伴说了如果黑客有很多个IP同时发起攻击呢?这点我一直也不是很想得通,但是一 般级别的黑客没这么多肉鸡,再者正常级别的Redis集群都能抗住这种级别的访问的,小公司 我想他们不会感兴趣的。把系统的高可用做好了,集群还是很能顶的。

 

缓存击穿的话,设置热点数据永远不过期。或者加上互斥锁就能搞定了

代码我肯定帮你们准备好了

面试结束

 

在此感谢B站up主,三太子敖丙,大家可以多多关注他哦。很牛的一位大佬。-->摘自B站 三太子敖丙

<think> 嗯,用户这次问的是Redis缓存问题的测试方法,正好结合之前讨论过的雪崩穿透击穿的概念。用户应该是运维或测试工程师,需要在实际环境中验证缓存机制的可靠性。 之前解释过三种问题的区别:雪崩是大面积失效,穿透是查询不存在数据击穿热点key失效。现在用户关心的是如何模拟这些场景进行测试,这很实用——毕竟线上故障的代价太大,提前测试能规避风险。 从引用材料看,[1]提到击穿的互斥锁和逻辑过期方案,[2][4]给出雪崩集群和TTL随机化方案,[3]则描述穿透的攻击特征。测试方法可以从这些解决方案逆推: 雪崩测试要模拟批量key同时过期,需要控制Redis的TTL设置;穿透测试要构造非法请求,得准备异常参数数据集;击穿测试最复杂,要精确控制单个热点key过期时间点并制造并发请求。 具体到技术实现: - 雪崩测试可以用Redis的批量过期命令或提前计算好TTL - 穿透测试需要脚本持续发送随机字符串等非常规参数 - 击穿测试的并发模拟工具选JMeter还是locust取决于用户技术栈 - 监控部分特别重要,比如grafana看数据QPS是否突增 用户可能还隐含需求:这些测试会不会影响线上服务?所以得强调在预发布环境操作。另外测试数据构造的实用性——比如穿透测试的非法参数要覆盖边界值(空值/超长字符串等)。 相关问题设计成递进的比较好:从检测工具到防御机制验证,最后到全链路压测,这样用户能阶梯式深入。 </think> 以下是针对Redis缓存雪崩穿透击穿的详细测试方法,结合引用材料和实际场景设计: --- ### 一、缓存雪崩测试方法 **核心目标**:验证批量缓存失效时数据的容灾能力 **测试步骤**: 1. **模拟批量失效** - 批量写入1000个测试Key,设置相同TTL(如30秒) - 使用`EXPIREALL`命令(需自定义Lua脚本)或等待自然过期 ```lua -- 批量设置过期脚本 for _,key in ipairs(KEYS) do redis.call('EXPIRE', key, 30) end ``` [^2][^4] 2. **制造高并发请求** - 使用JMeter/Locust模拟1000+并发请求这些Key - **监控指标**: - 数据QPS突增幅度(如从200QPS升至5000QPS) - Redis缓存命中率骤降至0% - 接口响应延迟是否超过阈值(如>500ms)[^4] 3. **验证防御机制** - 随机TTL方案:检查Key的TTL是否满足 $$ TTL_{real} = TTL_{base} + random(0, 300) $$ - 熔断机制:观察数据QPS超过阈值时是否触发请求拒绝[^2][^4] --- ### 二、缓存穿透测试方法 **核心目标**:验证对非法请求的拦截能力 **测试步骤**: 1. **构造非法请求** - 生成不存在Key的请求集(如负ID、UUID随机字符串) - 示例数据集:`["user_-1", "product_9999999", "order_abc123"]` 2. **发起持续攻击** - 以200QPS持续发送非法请求10分钟 - **关键监控点**: - Redis是否持续返回`nil` - 数据是否持续执行无效查询(如`SELECT * FROM users WHERE id=-1`)[^3] 3. **验证防御方案** - 布隆过滤器:检查非法Key是否被拦截(误判率需<0.1%) - 空值缓存:确认`user_-1`等Key被缓存为`""`且TTL=60s[^3] --- ### 三、缓存击穿测试方法 **核心目标**:验证热点Key失效时的并发控制能力 **测试步骤**: 1. **模拟热点Key失效** - 设置热点Key(如`hot_product_123`)并手动`DEL`触发过期 - 使用`redis-cli debug sleep 30`阻塞Redis模拟重建延迟 2. **制造并发重建请求** - 启动500个并发线程同时读取该Key - 监控数据连接数峰值(如从50激增至500)[^1] 3. **验证解决方案** - **互斥锁方案**: - 检查是否仅1个线程执行`SETNX lock_product_123 1` - 观察其他线程是否等待(响应延迟应≈缓存重建时间) - **逻辑过期方案**: - 修改逻辑过期字段为过去时间(如`expire_at: 1672500000`) - 验证是否返回旧数据并异步重建缓存[^1] --- ### 四、监控与断言设计 | 测试类型 | 通过标准(断言) | 监控工具 | |------------|------------------------------------------|-----------------------| | 雪崩测试 | 数据QPS增长<300%且不宕机 | Grafana + Prometheus | | 穿透测试 | 非法请求数据命中率=0% | Redis慢查询日志 | | 击穿测试 | 热点Key并发重建时数据连接数<最大连接数80% | Zabbix报警机制 | > 关键提示:所有测试需在**预发布环境**进行,避免影响线上服务[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值