空值缓存TTL应设60~180秒,需匹配业务SLA(如写入后120秒可查则设90秒),禁用null而用"__NULL__"或JSON结构,且必须配合接口层校验与限流。

空值缓存 + 合理 TTL 是防穿透最直接有效的手段,但“设个 5 分钟”就完事?不行。TTL 值不对、空值内容不规范、没配合校验,等于白搭。
空值缓存的 TTL 到底该设多少秒?
60~180 秒是实测较稳的区间,不是拍脑袋定的 300 秒。它得和业务节奏对齐:
- 太短(如
10秒):攻击者每秒发两次相同非法 ID,刚过期又打穿,防护形同虚设 - 太长(如
1800秒):新用户注册后 2 分钟可查,你却缓存空值 30 分钟,真实数据上线后用户查不到 - 推荐做法:若业务 SLA 要求“写入后
120秒内可查”,TTL 设为90秒;高频轮询接口可加随机偏移,如60 + ThreadLocalRandom.current().nextInt(30)
空值内容为什么不能直接存 null 或空字符串?
Spring Data Redis 对 null 的序列化行为不一致:有的版本存进去是 nil,取出来变成字符串 "null",业务层一判 == null 就误认为“查到数据”。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 安全写法:用明确标记,比如
"__NULL__"或new byte[0] - 读取时必须显式判断:
if ("__NULL__".equals(cached)) { return null; } - 更健壮的做法:序列化为 JSON,如
{"code":404,"msg":"not_found"},避免反序列化失败或类型混淆
为什么空值缓存必须和接口层校验一起用?
只靠缓存拦空请求,就像把锁装在门里——攻击者已经进屋了。很多非法请求根本不需要碰 Redis 或 DB。
- ID 类参数:在 Controller 层加
if (id 100000000L)直接return - 字符串 key:限制长度 ≤
32,字符集仅允许[a-zA-Z0-9_] - 高频空响应路径(如
/user/{id})加简单限流:rateLimiter.tryAcquire(1, 1, TimeUnit.SECONDS) - MyBatis-Plus 查询后手动补空缓存:
if (user == null) { redisTemplate.opsForValue().set(key, EMPTY_JSON, 90, TimeUnit.SECONDS); }
真正容易被忽略的是:大量空 key 过期后不会立刻释放内存。Redis 的惰性删除机制会让 INFO memory 显示 used_memory 持续虚高,尤其在批量导入新数据前被恶意刷过一轮空 key 的场景下,得靠定期 SCAN + DEL 清理,不能只依赖 TTL。

















