阿里面试:Redis缓存穿透怎么解决?别再只答缓存空值了
最近在复盘大厂常见的真实线上事故和面试真题时,发现一个极其经典的“翻车”场景。
一、场景引入:面试翻车现场
前几天,有个小伙伴去阿里面试。面试官抛出一个经典问题:“Redis缓存穿透怎么解决?”
小伙伴心里一喜,这题背过,于是自信回答:“缓存穿透就是查询不存在的key,请求打到数据库,这时候我们只要把空值缓存进Redis就行了。”
面试官微微一笑,继续追问:“那如果现在有人发起恶意攻击,用海量且不重复的随机ID疯狂请求你的接口,你每次都把这些随机生成的空值缓存起来,Redis的内存岂不是要被撑爆?”
小伙伴瞬间愣住,支支吾吾答不上来。很遗憾,这场面试基本就走远了。
二、问题拆解:缓存穿透到底在问什么?
在给出完美回答之前,我们要彻底搞懂什么是缓存穿透。
业务正常的逻辑是:先查Redis,有数据直接返回;没数据就查MySQL,查到了写回Redis并返回。 但缓存穿透指的是:查询一个在缓存和数据库中都绝对不存在的数据。
这就导致每次请求都会像隐形一样穿过Redis,直接重重地砸在数据库上。在遭到恶意攻击时,MySQL很容易因为连接数被打满或CPU飙升而宕机。面试官真正想考察的,不仅仅是你懂不懂概念,而是你有没有面对极端高并发和恶意攻击时的系统化防御思维。
三、核心方案:三层防护体系
作为架构师,我们在生产环境中绝不会只用一招,而是会构建一套纵深防御体系。
第一层防线:接口参数校验(大门安保)
这是最基础但也最容易被忽视的一层。在网关或应用入口处,直接拦截掉明显不合法的请求。比如:查询的商品ID必须是大于0的正整数、手机号格式必须严格符合正则。这一层成本极低,能把大部分低级的脚本攻击直接挡在系统门外。
第二层防线:布隆过滤器(核心安检通道)
这是解决大流量缓存穿透的真正核心方案。布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构。它的核心逻辑是:利用多个哈希函数和一个位图(BitMap)来快速判断一个元素是否存在。
查询布隆过滤器时:
- 如果它判断不存在,那数据一定不存在,请求直接丢弃,向前端返回空。
- 如果它判断存在,那数据可能存在(存在一定的误判率),这时候才允许请求继续往下走,去查缓存或数据库。
优点是占用内存极小,查询速度极快;缺点是存在一定的误判率,且原生不支持删除操作。
第三层防线:缓存空值 + 短过期(最后的兜底)
经过前面两层过滤,如果依然有极少量的穿透请求(比如布隆过滤器的误判)打到了数据库,并且数据库确实没查到数据,我们才会采用“缓存空值”的策略。
极其关键的一点:缓存空值必须设置一个非常短的过期时间(比如3到5分钟)。这样既能防止短期内同一个不存在的key频繁打库,又能避免恶意的大量随机key永久占用Redis宝贵的内存资源。
四、面试标准答案总结
当面试官再问起这个问题,你可以这样有条理地回答:
解决缓存穿透需要构建分层的防御体系,主要分为三步:
- 参数校验拦截:在应用层入口对请求参数做严格的合法性校验,从源头过滤无效请求。
- 布隆过滤器前置拦截:将所有存在的数据哈希到一个布隆过滤器中。请求过来先查布隆过滤器,判断数据大概率存在才放行,不存在则拦截。
- 缓存空值做兜底:如果请求还是打到了数据库且为空,就将空对象写入Redis,并强制设置一个较短的过期时间,以此作为最后一道防线。
五、生产环境避坑指南
除了八股文,面试官往往更喜欢听听你在实战中的经验。你可以补充这几点:
- 应对布隆过滤器的误判:可以通过调大布隆过滤器的容量或增加Hash函数数量来降低误判率,配合最后一步的缓存空值来处理那极少部分漏网之鱼。
- 分布式架构下的一致性:在分布式微服务架构中,本地的布隆过滤器很难同步,生产环境中通常会使用基于Redis 的 Bitmap来集中式存储和实现分布式的布隆过滤器。
- 监控与报警:对于空值缓存被频繁命中的情况,必须配置监控大屏和限流策略,一旦触发阈值立刻报警人工介入。
写在最后
这道题表面上是在问Redis,实际上是在考察你的系统化设计能力和严谨的工程思维。从单一防御到分层防御,这就是普通开发和资深架构师的区别。
关于Redis的高级面试题,除了穿透,还有缓存击穿、缓存雪崩、热点Key等经典连环问。
