缓存空对象和布隆过滤器适用场景不同:前者适用于低频、可预估的无效key,后者适用于高频、不可穷举的恶意扫描;两者需按“先布隆→再缓存→最后DB”顺序协同使用。

缓存空对象和布隆过滤器都能缓解缓存穿透,但适用场景完全不同:缓存空对象适合低频、可预估的无效 key(比如已删除的用户 ID),布隆过滤器更适合高频、不可穷举的恶意扫描(比如爬虫遍历 /user?id=1 到 /user?id=9999999)。
缓存空对象:简单但有陷阱
核心思路是把查不到的结果也写进 Redis,设较短过期时间(如 2–5 分钟),让后续相同请求直接命中空值,不打数据库。
常见错误现象:setex user:10086 "" 300 存空字符串,但业务层未区分“查到空对象”和“缓存未命中”,导致逻辑误判;或过期时间设太长,真实数据插入后长期无法生效。
- 必须统一约定空对象的序列化格式,推荐用
JSON.stringify({__empty__: true}),避免和合法空字符串、null 混淆 - 空对象过期时间不能固定写死,建议按业务冷热动态调整——例如用户中心类接口可用 120 秒,商品详情类可缩至 30 秒
- 注意内存膨胀:如果攻击者构造大量随机 key(如
user:abc123、user:def456),每个都缓存空值,Redis 内存会快速耗尽
布隆过滤器:省内存但需预加载
布隆过滤器本质是个位数组 + 多个哈希函数,只支持“可能存在”或“肯定不存在”的判断。它不存原始数据,所以内存占用极小,但要求所有合法 key 在查询前就已写入过滤器。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
使用场景:用户 ID、订单号等有明确生成规则或可离线导出的 ID 集合;不适合手机号、邮箱等可能随时新增且无规律的字段。
- Redis 6.2+ 原生支持
BF.RESERVE/BF.ADD,但生产环境更推荐用客户端布隆(如 Java 的guava BloomFilter或 Go 的gotip/bloom),避免 Redis 成为单点瓶颈 - 务必设置合理误差率(
error_rate),默认 0.01(1%)对大多数业务足够;调低到 0.001 会使内存翻倍,通常没必要 - 过滤器不支持删除,一旦误删或漏加 key,只能重建——建议搭配定时任务每日全量重建,并用双写机制过渡
两者混用时的关键顺序
不是“先查布隆再查缓存”,而是“先查布隆 → 布隆说不存在就直接返回 → 存在才查缓存 → 缓存未命中再查 DB → DB 也没才写空对象”。顺序错一步,布隆就形同虚设。
典型错误配置:if bloom.mightContain(key) { return cache.get(key) },这会导致布隆误判为“可能存在”时,跳过缓存直查 DB,完全失去保护作用。
- 布隆过滤器必须部署在缓存之前,作为第一道拦截;它不解决缓存击穿或雪崩,只管“这个 key 本就不该存在”
- 空对象仍需保留,用于兜底布隆漏判(虽然概率极低)和覆盖布隆未及时更新的窗口期
- 监控重点应放在
bloom.mightContain(key) == true but db.get(key) == null的比例,若持续高于 0.1%,说明布隆初始化遗漏或 key 生成逻辑变更未同步
真正难的不是选哪个方案,而是搞清你的非法请求到底来自哪里:是运营误配的旧链接,还是黑产自动化脚本?前者加个空对象就能止血,后者不建布隆,光靠 TTL 根本扛不住。

















