固定过期时间易引发缓存雪崩,需用偏移区间随机TTL(如3600±180秒)并复用Random实例;Caffeine通过expireAfterWrite与expireAfterAccess组合实现软随机,须开启recordStats监控命中率;@Cacheable下可通过自定义RedisCacheWriter注入随机逻辑。

固定过期时间是缓存雪崩最直接的导火索,单纯给所有 key 设置统一的 expireAfterWrite=30m,在高并发写入场景下极易导致整点级失效风暴。必须让过期时间“散开”,再叠加本地缓存兜底,才能真正压住雪崩风险。
Redis 缓存层怎么加随机 TTL(不是简单 random.nextInt)
Spring Boot 的 @Cacheable 默认不支持 per-key 随机过期,直接在注解里写 unless="#result == null" 或硬编码 entryTtl 都无效——它只认全局配置。真要实现随机,得绕过注解,改用 RedisTemplate 手动设值:
- 不要依赖
RedisCacheManager的默认entryTtl,那只是静态值 - 在业务逻辑中显式调用
redisTemplate.opsForValue().set(key, value, ttl, TimeUnit.SECONDS),其中ttl由随机生成器输出 - 推荐用偏移区间而非纯随机:比如基础 3600 秒,±180 秒波动,避免某些 key 过期太快(
3600 + random.nextInt(360) - 180) - 注意
Random实例复用问题:别在方法里 newRandom(),应注入单例或用ThreadLocalRandom.current()
Caffeine 本地缓存如何配合随机策略防穿透+降压
Caffeine 本身不支持运行时动态调整单个 entry 的过期时间,但它的 expireAfterWrite 和 expireAfterAccess 可以组合使用,形成“软随机”效果:
-
expireAfterWrite(Duration.ofMinutes(5))控制写入后最大存活,防脏数据滞留 -
expireAfterAccess(Duration.ofMinutes(2))让冷 key 自动淘汰,相当于对访问频次做了隐式分流 - 关键点:必须开启
recordStats(),否则无法监控命中率跌落——雪崩前兆往往就是cache.getIfPresent()命中率从 95% 突降到 40% - 别把
Caffeine当 Redis 替代:它不共享、不一致,只适合读多写少且容忍短时 stale 的场景(如用户配置、地区字典)
@Cacheable 注解下怎么不破坏现有代码结构加随机
如果项目已大量使用 @Cacheable(cacheNames = "users", key = "#id"),又不想重构成 RedisTemplate 调用,可行路径只有一条:自定义 RedisCacheWriter。
- 继承
DefaultRedisCacheWriter,重写put方法,在调用父类前对ttl参数做扰动 - 在
RedisCacheConfiguration中通过cacheWriter(...)注入该实现 - 注意:此方式对所有
@Cacheable生效,无法按 cacheName 区分策略;若需差异化(如 “users” 随机、“configs” 固定),得在 writer 内部加路由逻辑 - 性能影响极小:一次
Math.random()调用,远低于序列化/网络开销
真正的难点不在加随机,而在于监控和收敛——你得能实时看到各 cacheName 的平均 TTL 分布、Caffeine 命中衰减曲线、Redis 连接池 wait-time 突增点。没有这些,随机只是自我安慰。


















