缓存粒度设计与穿透、击穿、雪崩防御是环环相扣的系统工程:粒度影响缓存效率与一致性,而三大异常防御需结合分层缓存、布隆过滤、分布式锁、ttl随机化及熔断降级等策略协同应对。

缓存粒度设计和三大异常(穿透、击穿、雪崩)的防御不是孤立问题,而是环环相扣的系统工程。粒度太粗,缓存利用率低、更新成本高;粒度过细,key爆炸、内存浪费、一致性难控——而无论粒度如何,若缺乏对应防御机制,再好的设计也会在高并发下瞬间崩塌。关键在于“按需分层 + 精准拦截 + 弹性兜底”。
缓存粒度:从场景出发,拒绝一刀切
粒度选择本质是权衡空间、更新频率与一致性要求:
- 粗粒度缓存(如整张用户订单列表):适合读多写少、变更不频繁的聚合数据;但更新时需全量刷新,易引发雪崩风险,且单次缓存命中收益高、miss代价也高。
- 细粒度缓存(如单个订单项 order:1001:item:2001):更新灵活、一致性好,但key数量激增,布隆过滤器维护成本上升,空值缓存策略也更难收敛。
- 混合粒度:推荐主流做法——核心实体用细粒度(user:1001、product:888),高频组合查询用适度聚合(cart:user:1001、recent_orders:user:1001:7d),并通过本地缓存(Caffeine)对细粒度key做短期热点缓冲。
穿透防御:先筛后查,双保险拦截无效请求
穿透本质是“无效key打穿所有层”,防御重点在入口侧过滤与缓存层兜底:
- 网关或服务入口集成布隆过滤器(Bloom Filter),预加载所有合法ID集合(如用户ID、商品SKU);对肯定不存在的请求直接拦截,不进业务逻辑。
- 对未命中缓存的查询,无论数据库是否返回null,都写入空值缓存(如 value = “null” 或自定义占位对象),并设置较短TTL(如 2–5 分钟),避免重复穿透。
- 对ID类参数增加基础校验(如正整数、长度范围、前缀规则),在Controller层快速拒绝明显非法输入,减少无效流量进入缓存链路。
击穿防护:锁+重试+本地缓存,稳住热点生命线
击穿聚焦单个热点key过期瞬间的并发冲击,核心是“错峰重建 + 避免重复加载”:
- 使用分布式锁(Redisson RLock 或 SETNX + Lua)控制重建权限,确保同一时刻仅一个线程查库写缓存。
- 采用双重检查(Double-Check):加锁后再次查缓存,防止锁等待期间其他线程已写入,避免冗余DB查询。
- 搭配本地缓存(如 Caffeine)作为第一道屏障,对热点key设置较长的expireAfterWrite(如10分钟),即使Redis中key过期,本地仍可短暂兜底,大幅降低Redis和DB压力。
雪崩应对:时间分散 + 多级缓冲 + 熔断降级
雪崩源于大量key集体失效或缓存服务不可用,需从生成、存储、降级三层面设防:
- TTL随机化:基础过期时间 + 随机偏移(如 3600 ± 300 秒),打破集中过期节奏;对强时效性数据(如秒杀库存),改用逻辑过期(缓存value内嵌expireTime字段,由业务线程异步刷新)。
- 二级缓存架构:Caffeine(本地)+ Redis(远程)。本地缓存命中率通常可达70%–90%,天然隔离Redis抖动影响;本地miss后再查Redis,Redis miss才查DB。
- 熔断与降级:接入Sentinel或Resilience4j,在DB响应超时或错误率超标时,自动触发降级逻辑(如返回兜底静态页、缓存历史快照、或简化数据结构),保障服务可用性而非强一致性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











