能,但仅对非法参数或恶意构造的不存在key有效;需主动写入可识别占位值并设2–5分钟过期,否则易致内存爆炸,建议结合布隆过滤器或逻辑过期方案。

缓存空对象到底能不能防穿透
能,但只在特定条件下有效。缓存空对象(即把 NULL 或空字符串、空 JSON 等显式写入 Redis)本质是用空间换时间,让后续相同 key 的请求直接命中缓存,不再打到后端 DB。但它对「参数非法、恶意构造不存在 key」这类穿透最有效;对「真实存在但刚被删掉」的场景,需配合逻辑过期或布隆过滤器。
注意:Redis 不会自动区分“查无此数据”和“查出 null”,你得在业务代码里主动判断并写入空值——否则缓存里压根没这条记录,照样穿透。
空对象该存什么值、设多久过期
空对象不是随便塞个 null 就完事。Java 客户端(如 Lettuce/Jedis)序列化时,null 可能被忽略或抛异常;Go 的 redis.Set 传 nil 会报错;Python 的 redis.set(key, None) 实际存的是字符串 "None",容易误判。
实操建议:
- 统一用可识别的占位值,比如字符串
"__NULL__"或 JSON{"code": 404, "data": null} - 过期时间必须设,且不宜过长——一般 2–5 分钟足够。过长会导致“刚删的数据查不到”,过短则起不到缓冲作用
- 避免用永不过期(
EXPIRE key -1),否则空 key 永久堆积,内存只增不减
空对象引发的内存爆炸风险
空对象最大的坑不是功能失效,而是被当成“正常缓存”一样放任增长。尤其当接口支持模糊查询、分页参数拼接 key(如 user:search:name:xxx:page:1),攻击者批量请求随机 name,就会生成海量空 key。
典型现象:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
INFO memory显示used_memory_human持续上涨,但db0:keys=1000却只有几百个“有效 key” -
redis-cli --bigkeys扫出大量小 value(几十字节)、高 TTL 的 key,名字带明显规律(如含id=9999999) - RDB/AOF 文件体积异常膨胀,备份恢复变慢
缓解手段:
- 加前缀隔离:给空对象 key 加独立命名空间,如
empty:user:123,方便单独清理或监控 - 限速+采样:对高频空返回的 key(如 1 分钟内超 10 次),临时拒绝或降级,不写缓存
- 定期扫描清理:用
SCAN配合TYPE和TTL找出长期未访问的空 key,脚本定时剔除
比空对象更稳的替代方案 空对象是“补漏”,不是“根治”。真正高并发、高敏感的系统,通常组合使用:
布隆过滤器(Bloom Filter)前置校验:请求先过本地或 Redis Module 的布隆过滤器,大概率拦截无效 key。注意它有误判率(false positive),但绝不会漏判(false negative)
- 初始化需加载全量有效 key,适合数据相对静态的场景(如商品 ID、用户 UID)
- 不适用动态生成 key(如时间戳、UUID)或高频变更数据
逻辑过期 + 空值标记:查 DB 返回 null 时,不直接缓存空值,而是缓存一个带过期字段的对象(如 {"data": null, "expire_at": 1717023456}),应用层解析后自行判断是否需重建
- 避免空 key 占用独立 slot,降低 Redis 内存碎片
- 需要客户端多一层解析逻辑,但更可控

















