跳转到主要内容

Redis 缓存设计

缓存穿透、击穿、雪崩的成因与应对,Cache-Aside 与一致性,大 key 热 key,过期与淘汰策略。

引入缓存能显著降低数据库压力,但设计不当会引入穿透、击穿、雪崩等经典问题。下面逐一拆解成因与对策。

三大经典问题

  • 缓存穿透:查询不存在的数据,缓存与数据库都查不到,请求每次都打到 DB。应对:缓存空值(短过期)、布隆过滤器拦截非法 key。
  • 缓存击穿:某个热点 key 过期瞬间,大量并发同时回源 DB。应对:互斥锁(只放一个线程重建)、逻辑过期(异步刷新)、热点 key 不过期。
  • 缓存雪崩:大量 key 同一时刻集中失效,或 Redis 整体不可用,DB 被冲垮。应对:过期时间加随机抖动、多级缓存、Redis 高可用(哨兵/集群)。

Cache-Aside 与一致性

最常用的是 Cache-Aside(旁路缓存)

读: 先读缓存 -> 命中返回; 未命中读 DB -> 写入缓存
写: 先更新 DB -> 再删除缓存 (而非更新缓存)

「先更新 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-lruallkeys-lfu,并为关键数据设置合理 TTL,结合抖动避免雪崩。