缓存空值内存开销大且易被滥用,单个空值占100–200字节,恶意请求可致秒级内存耗尽;布隆过滤器仅需几MB即可支撑千万级存在性判断,并在Redis前拦截无效请求,杜绝空值写入,但存在误判率、无漏判,且不支持删除。

会,但不是必然——关键看你怎么用 set 写空值,以及有没有前置拦截。
缓存空值的内存开销到底有多大?
单个空值 key 在 Redis 里实际占用约 100–200 字节(含 dictEntry、sds 结构、key 名长度等)。看起来不多,但恶意请求一上来就是几万随机 user:123456789、order:abcde,内存就不是“慢慢涨”,而是“秒满”。更麻烦的是:allkeys-lru 淘汰策略对空值基本无效——它从不被访问,根本不会进入 LRU 链表。
常见踩坑点:
- 把空值 TTL 设成和正常数据一样长(比如
3600秒),等于给攻击者免费建了个“空 key 停车场” - 没加前缀,直接缓存裸 ID(如
"12345"),后期无法用SCAN cache_null:user:* COUNT 1000批量清理 - 没监控
DBSIZE和used_memory_human,等 OOM 报错command not allowed when used memory > 'maxmemory'才发现
布隆过滤器为什么能大幅降低内存压力?
它不存 key,只存哈希位。千万级 key 的存在性判断,用 Redis 原生 BF.ADD / BF.EXISTS,通常只需几 MB 内存。而且它在缓存之前就拦截:如果 BloomFilter.mightContain(id) 返回 false,连 Redis 都不查,自然也不会写空值。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
注意两个硬约束:
- 布隆过滤器有误判率(false positive),但绝无漏判(false negative)——它说“不存在”,那就一定不存在;说“可能存在”,才继续走缓存 → DB 流程
- 原生 Redis
BloomFilter不支持删除,如果业务有频繁删数据场景,得换Counting Bloom Filter或配合定时重建
空值缓存 TTL 到底设多少秒才安全?
没有通用值,但必须满足一个前提:短于业务可接受的“新数据延迟可见时间”。比如用户注册后要求 2 秒内能查到,那空值 TTL 就不能超过 2 秒。实测中 redisTemplate.opsForValue().set(key, "NULL", 2, TimeUnit.SECONDS) 能扛住每秒几百次恶意 ID 查询,且内存可控。
更稳妥的做法是分级:
- 用户 ID 类:TTL =
2秒 - 订单号类:TTL =
5秒(格式更固定,误撞概率低) - 配置项类:干脆不缓存空值,靠接口层校验拦掉
真正难的不是写那一行 set,而是想清楚:这个空值,到底该在缓存里“活”多久,以及它有没有资格活过第一道布隆过滤器。

















