@Cacheable 加 Redis 之后,穿透、击穿、雪崩各要在哪里配置?cache-null-values 的默认值是什么?sync = true 真的能防击穿吗?TTL 怎么加随机?这篇在 Spring Boot 4.0.8 加 Redis 上逐个实测。
byId(1) 两次、byId(2) 一次:方法体真正执行了 2 次;CacheManager = RedisCacheManager redis 里的 key b'users::1':TTL = -1(-1 表示永不过期),value 13 字节 redis 里的 key b'users::2':TTL = -1(-1 表示永不过期),value 13 字节 byId(1) 两次、byId(2) 一次:方法体真正执行了 2 次;CacheManager = RedisCacheManager 加 spring.cache.redis.time-to-live=60s 之后:[(b'users::1', 60), (b'users::2', 60)] byId(1) 两次、byId(2) 一次:方法体真正执行了 2 次;CacheManager = RedisCacheManager 加 spring.cache.redis.use-key-prefix=false 之后 key:[b'1', b'2']
key 是「缓存名::key」,默认永不过期;time-to-live 是全局设置。
nullable(999) 调两次(方法体永远返回 null):方法体执行 1 次 nullableUnless(999) 调两次(方法体永远返回 null):方法体执行 2 次 redis 里留下的 key:[(b'users::999', 60, 64)](第一个是缓存了 null 的 users::999) cache-null-values=false:nullable(999) 调两次(方法体永远返回 null):方法体执行 1 次;异常 IllegalArgumentException:Cache 'users' does not allow 'null' values; Avoid storing null via '@Cacheable(unless="#result == null")' or configure RedisCache to allow 'null' via RedisCacheConfiguration cache-null-values=false:nullableUnless(999) 调两次(方法体永远返回 null):方法体执行 2 次
cache-null-values 默认 true,null 也被缓存;unless 可以不缓存 null;关掉后遇到 null 会抛异常。
sync = false(默认):30 个线程同时请求同一个冷 key,方法体执行 30 次,总用时 582 ms
sync = true:30 个线程同时请求同一个冷 key,方法体执行 30 次,总用时 569 ms
sync = true,写入器换成 lockingRedisCacheWriter:30 个线程同时请求同一个冷 key,方法体执行 1 次,总用时 995 ms
-- 两个进程(模拟两个实例)同时请求同一个冷 key,sync = true + lockingRedisCacheWriter:
sync = true,写入器换成 lockingRedisCacheWriter:30 个线程同时请求同一个冷 key,方法体执行 1 次,总用时 1141 ms
sync = true,写入器换成 lockingRedisCacheWriter:30 个线程同时请求同一个冷 key,方法体执行 0 次,总用时 1191 ms
两个进程的方法体执行次数相加 = 1sync = true 要配合 lockingRedisCacheWriter 才有效,代价是等锁;锁在 Redis 里所以跨实例也有效。
写入完成:users 100 个、jitter 100 个 users(全局统一 TTL 20 秒):100 个 key 的剩余 TTL 取值 [20] jitter(entryTtl 用 TtlFunction,10~19 秒随机):100 个 key 的剩余 TTL 最小 10、最大 19,不同的取值有 10 个
统一 TTL 会同时过期;用 TtlFunction 给 TTL 加随机。