Redis 缓存雪崩对策
数据存储805 字预计 2 分钟阅读
详细剖析缓存雪崩、穿透和击穿三大高并发灾难问题,提供生产级的实战防灾对策。
引言
在高并发系统架构中,缓存(Redis)是抗住大流量的先锋队,而底层的数据库(MySQL)是最后坚守的阵地。如果缓存系统因为某种故障或配置不合理导致瞬间崩塌,庞大的请求流量会像洪峰一样直奔数据库,瞬间压垮后端服务。本文将逐一击破这三大灾难性问题。
缓存雪崩 (Cache Avalanche)
问题定义
当大量缓存数据在同一时间集中失效(过期),或者 Redis 服务整体发生宕机时,所有原本应当由缓存承载的读请求都会转而访问数据库,导致数据库负荷骤增,甚至宕机引发链式反应。
解决方案
- 设置随机过期时间:在批量将数据写入缓存时,在固定的过期时间(例如 2 小时)上,额外加上一个随机秒数(如 1 - 5 分钟),防止数据在同一秒内集体过期。
- 构建高可用缓存集群:通过部署 Redis Sentinel(哨兵)或 Redis Cluster,消除单点故障风险。
- 开启限流与熔断:在网关层或业务层引入限流,当检测到数据库压力过大时,直接熔断非核心业务,返回降级数据。
缓存击穿 (Cache Breakdown)
问题定义
某个热点 key(通常是爆款商品或重大新闻),在持续承受极其庞大的并发读请求期间,突然过期失效。此时,瞬间涌入的无数线程会并发读取该 key,发现缓存没有后,会同时向底层数据库发送查询请求。
解决方案
- 互斥锁机制 (Mutex Lock):当缓存失效时,不让所有线程同时访问数据库。而是通过
SETNX获取一个互斥锁,只有拿到锁的这一个线程负责去读取数据库并重建缓存,其他线程则等待重试:if (!cacheValue) { if (getLock(lockKey)) { cacheValue = db.query(); setCache(key, cacheValue); releaseLock(lockKey); } else { sleep(100); return getCache(key); } } - 热点数据永不过期:对于最核心的运营活动页面数据,不设置过期时间。而是由后台监控程序或消息队列异步检测并主动刷新缓存内容。
缓存穿透 (Cache Penetration)
问题定义
用户请求的数据在缓存和数据库中都完全不存在(例如有人故意传入不存在的用户 ID 10000000 遍历进行攻击)。因为数据不存在,缓存中不会写入,每次请求都会“穿透”缓存直达数据库,给数据库带来无效开销。
解决方案
- 缓存空值或默认值:一旦从数据库查询无果,依然向缓存中写入一个特殊的空标记(如
key: "null"),并设置一个较短的过期时间(如 60 秒),防止相同请求频繁穿透。 - 布隆过滤器 (Bloom Filter):将所有可能存在的数据的哈希值全部映射到一个超小的 Bit 数组中。当请求进来时,先用布隆过滤器判断该数据是否存在,若判断不存在则直接拒绝,防止无效查询直达数据库。