Redis缓存穿透怎么破?聊聊防护数据库安全那些事儿
- 问答
- 2026-01-11 19:01:30
- 4
说到Redis缓存穿透,咱们可以把它想象成一个超市的奇葩情况,正常情况下,顾客想买可乐(这相当于一个数据请求),会先到入口处的快速取货区(这就是Redis缓存)看看,如果有,拿了就走,又快又方便,如果快速取货区没有,顾客才会去后面巨大的仓库(这就是数据库)里找,找到后,不仅自己拿走商品,还会聪明地放几瓶到快速取货区,方便下一个顾客。
那什么是缓存穿透呢?就是有个捣蛋鬼,他老是来问一些超市根本就不会卖的东西,你们这有航空母舰吗?”或者“给我来一匹活生生的斑马!”(这相当于查询一个数据库中根本不存在的数据)。
这个请求来了,快速取货区(Redis)肯定没有啊,因为从来没进过这种货,于是请求只能跑到后面的大仓库(数据库)去查,仓库管理员翻了个底朝天,发现压根没有这东西,只能告诉捣蛋鬼“没有”,关键是,这种“航空母舰”和“斑马”的请求,这次查完了,也不会在快速取货区留下任何记录(因为数据库没有,缓存里也就没法存一个“空结果”)。
可怕的地方来了:如果这个捣蛋鬼不死心,或者干脆用机器一秒内发起成千上万个这种乱七八糟的请求,那么每个请求都会直接穿透快速取货区,重重地砸在仓库(数据库)身上,仓库管理员(数据库服务器)累死累活地每次都要全力搜索,最后都回报“没有”,短时间内海量的这种无效请求,会把仓库管理员彻底累垮(数据库压力激增,性能急剧下降甚至崩溃),导致那些想正常买可乐、买薯片的 honest 顾客(正常业务请求)也得不到响应了,这就是缓存穿透的危害。

怎么破解这个难题呢?咱们聊聊几个实用的办法,核心思想就是:别让那些明知道不存在的请求,老是去麻烦数据库。
第一招,给“没有”的结果也打个临时标签——缓存空对象。 (此方法在众多技术博客和论坛中均有提及,是基础解决方案之一) 还是那个例子,当捣蛋鬼第一次来问“有航空母舰吗?”的时候,仓库管理员查完说“没有”,这时,聪明的超市经理可以在快速取货区贴一张小纸条,写上“本店无航空母舰”,并设置一个有效期,比如5分钟,那么在接下来的5分钟内,如果再有人(不管是捣蛋鬼还是好奇宝宝)来问同样的问题,快速取货区的工作人员一看纸条,就能直接回复“没有”,这个请求就被拦住了,根本不会再去麻烦仓库,这就大大减轻了数据库的压力。 不过这个方法有个小缺点:如果捣蛋鬼有无穷无尽、花样百出的不存在商品词(比如问完航空母舰问太空飞船,问完恐龙化石问美人鱼),那么快速取货区可能会被各种“本店无XXX”的纸条占满,挤占了正常商品的空间(占用Redis内存),所以需要设置一个较短的有效期,并且监控内存使用情况。

第二招,在进超市大门前就设一道安检——布隆过滤器。 (布隆过滤器是计算机科学中的一个经典数据结构,常用于解决此类问题) 这个办法更主动,我们在所有商品入库到仓库之前,先用一个特殊的、非常节省空间的“魔法筛子”(布隆过滤器)把所有的商品名都登记一遍,这个筛子有个特点:它可能会误伤好人,但绝不会放过一个坏人。 当顾客(请求)来到超市门口时,需要先过这个“魔法筛子”,顾客问:“有可乐吗?”筛子一查登记簿,说:“嗯,有这个商品,您请进快速取货区看看。” 如果顾客问:“有航空母舰吗?”筛子一查,肯定地说:“绝对没有!我们登记簿上压根没这玩意儿,您请回吧。” 这样,那些明显不存在的请求,在最早期的入口就被拦截了,连快速取货区都到不了,更别说去冲击仓库(数据库)了。 为什么说“可能误伤好人”呢?因为这种筛子有一定的误差率,有极小的可能性会把一个实际存在的商品误判为不存在(比如一种非常冷门、刚入库还没来得及登记的新品),但这种情况概率很低,可以通过调整筛子的精确度来控制,对于防护穿透来说,这个代价是完全可以接受的。
第三招,规范购物流程——做好基础校验。 (这是最基本的软件设计原则,适用于所有系统) 这个方法最简单也最有效,我们超市卖的商品ID都是数字,从1到10000,如果有个人上来就查询商品ID为“-1”或者“9999999”的商品,这明显就不符合规矩啊,在请求到达缓存和数据库之前,我们的系统就应该直接把这个非法请求驳回,并返回错误提示,根本不需要去查询,这就好比超市门口立个牌子:“本店商品编号为1-10000,请查询有效编号。” 对于明显的无效参数,直接在业务层进行校验和过滤,能从源头上减少大量无效请求。
除了应对缓存穿透,守护数据库安全还有很多其他要注意的事儿,要防止“缓存击穿”(指的是某个热点key突然过期,导致大量请求同时砸向数据库),解决办法可能是设置永不过期,或者使用互斥锁让只有一个请求去数据库加载数据,还要防止“缓存雪崩”(指大量key在同一时间点过期,导致请求批量涌向数据库),可以通过给缓存过期时间加上随机值来避免集体失效。
保护数据库就像保护一个核心重地,不能让它直接暴露在所有流量面前,Redis作为缓存,本身就是一道重要的防线,我们要做的是加固这道防线,并通过布隆过滤器、参数校验等手段,建立多层次、立体的防护体系,确保那些无效的、恶意的流量在到达数据库之前就被层层过滤掉,从而保证整个系统的稳定和高效运行。
本文由帖慧艳于2026-01-11发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://waw.haoid.cn/wenda/78856.html
