Redis 缓存设计
缓存穿透、击穿、雪崩的成因与应对,Cache-Aside 与一致性,大 key 热 key,过期与淘汰策略。
引入缓存能显著降低数据库压力,但设计不当会引入穿透、击穿、雪崩等经典问题。下面逐一拆解成因与对策。
三大经典问题
- 缓存穿透:查询不存在的数据,缓存与数据库都查不到,请求每次都打到 DB。应对:缓存空值(短过期)、布隆过滤器拦截非法 key。
- 缓存击穿:某个热点 key 过期瞬间,大量并发同时回源 DB。应对:互斥锁(只放一个线程重建)、逻辑过期(异步刷新)、热点 key 不过期。
- 缓存雪崩:大量 key 同一时刻集中失效,或 Redis 整体不可用,DB 被冲垮。应对:过期时间加随机抖动、多级缓存、Redis 高可用(哨兵/集群)。
Cache-Aside 与一致性
最常用的是 Cache-Aside(旁路缓存):
「先更新 DB 再删缓存」可降低并发下读到旧值的概率;极端不一致可通过延迟双删或订阅 binlog(如 Canal)补偿。注意:不要盲目「更新缓存」,否则并发写可能产生脏数据。
大 key 与热 key
- 大 key:如包含百万元素的 hash/list,删除或序列化会阻塞主线程。应对:拆分、分批删除(
unlink)、定期清理。 - 热 key:单个 key 访问极高,单节点成为瓶颈。应对:本地缓存副本、key 打散到多个副本、Redis 集群分片。
过期与淘汰策略
Redis 提供主动 + 惰性两种过期删除,内存不足时按 maxmemory-policy 淘汰:
allkeys-lru/volatile-lru:最近最少使用allkeys-lfu/volatile-lfu:最不经常使用volatile-ttl:优先淘汰即将过期者noeviction:不淘汰,写报错(默认)
缓存场景通常选 allkeys-lru 或 allkeys-lfu,并为关键数据设置合理 TTL,结合抖动避免雪崩。