在高并发架构中,Redis常被用作MySQL等关系型数据库的前置缓存层,以拦截热点查询并降低后端压力。然而,当缓存未命中或集中失效时,请求会直接穿透至数据库,引发性能瓶颈甚至服务崩溃。本文将系统梳理缓存穿透、缓存击穿与缓存雪崩的触发条件,并提供对应的工程级解决方案,帮助开发者快速定位风险并实施防护。
缓存穿透的原理与拦截方案
Redis通常与MySQL等持久层数据库配合使用,将高频访问的热点数据提前加载到内存中。当客户端发起查询时,系统优先读取Redis缓存;若缓存未命中,则回源至MySQL查询,并将结果写回Redis供后续请求复用。这一流程显著降低了数据库的读取压力,但在特定场景下会暴露安全隐患。

缓存穿透是指客户端查询的数据在Redis和MySQL中均不存在。此时MySQL返回空结果,若攻击者或异常逻辑持续发起此类无效请求,大量回源查询将直接压垮数据库。为阻断此类流量,可采用以下两种方案:
缓存空对象
当MySQL确认数据不存在并返回空值时,Redis将该空对象写入缓存,并设置较短的过期时间(如30秒至5分钟)。后续相同请求将直接命中缓存中的空值,从而避免重复回源。该方案实现简单,但需注意空对象会占用Redis内存空间,且可能被恶意构造的大量不同key耗尽资源。
布隆过滤器前置校验
布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构,其核心特性是:若判定某数据不存在,则该数据一定不存在;若判定存在,则可能存在误判。利用这一特性,可在请求到达缓存层前进行拦截。
系统启动时,将合法的热点数据key加载至布隆过滤器(即缓存预热)。当新请求到来时,先经过布隆过滤器校验:若过滤器判定key不存在,则直接拒绝请求;若判定存在,则继续执行Redis与MySQL的查询流程。该方法能高效过滤绝大多数无效请求,显著降低缓存穿透风险。

缓存击穿的成因与并发控制
缓存击穿与穿透不同,它针对的是真实存在的数据。当某个热点key的缓存突然过期,而该key正承受极高的并发访问时,大量请求会瞬间穿透缓存层,同时涌向MySQL数据库,导致数据库连接池耗尽或响应延迟飙升。
解决缓存击穿的核心思路是控制并发回源的数量,避免数据库被瞬时流量打满:
设置热点数据永不过期
对于访问频率极高且数据变更不频繁的核心热点key,可直接移除过期时间,使其常驻Redis内存。该方案彻底消除了过期导致的击穿风险,但需配合后台异步更新机制,确保数据一致性。
分布式锁串行化回源
通过分布式锁机制,确保同一时刻只有一个线程负责从数据库加载数据并重建缓存,其余线程等待缓存就绪后直接读取。具体流程如下:
- 加锁:查询缓存未命中后,尝试获取分布式锁。首个获取锁的线程进入数据库查询,并将结果写入Redis。
- 等待与释放:未获取锁的线程进入阻塞或短暂轮询等待。当持有锁的线程完成数据加载并释放锁后,其他线程依次读取已更新的缓存,避免重复查询数据库。
该方案能有效削峰填谷,但需注意锁的超时设置与死锁预防,通常可借助Redisson等成熟客户端实现。
缓存雪崩的风险与过期策略
缓存雪崩是指大量缓存key在同一时间段集中过期,恰逢业务高峰期,导致海量请求同时回源至数据库,引发数据库负载骤增甚至宕机。与缓存击穿针对单个热点key不同,雪崩是全局性或大批量key的集体失效,影响范围更广、破坏力更强。
防范缓存雪崩的关键在于打散过期时间,避免集中失效:
- 热点数据永不过期:与击穿防护类似,对核心业务数据设置永久缓存,从根源上减少过期事件。
- 随机化过期时间:为缓存key设置基础过期时间后,叠加一个随机偏移量(如±10%)。例如,原计划1小时过期的key,实际过期时间分布在54分钟至66分钟之间。通过时间分散,可有效避免大批量key同时失效。
在实际架构中,通常将布隆过滤器、分布式锁与随机过期策略组合使用,并配合服务降级、限流与数据库连接池优化,构建多层防御体系,确保缓存层在高并发场景下的稳定性。
