0%

Redis布隆过滤器

见龙在田,利见大人。 —— 《易经》之乾卦的第二爻(九二爻) 译为一个胸怀大志的人,已经崭露头角。今指一个人仕途顺利,初露锋芒,得到领导的赏识,前途光明。

一、基础

  1. 概念

      布隆过滤器(Bloom Filter)是1970年由布隆提出的,是一个很长的二进制向量和一系列随机映射函数。实质上,它是一种概率型数据结构(probabilistic data structure),其特点是高效地插入和查询,可以用来快速判断某个元素存在或不存在,空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

✅ 特点:插入、查询速度极高,空间效率远超普通集合
❌ 局限:存在假阳性误判(判断存在不一定真存在),普通布隆不支持删除元素

核心特性总结

  • 无假阴性:如果元素真实存在,查询一定返回“可能存在”;
  • 有假阳性:元素不存在,也有可能巧合判定为“可能存在”。

适用场景:网页黑名单、垃圾邮件过滤、爬虫URL判重、Redis缓存穿透防护、账号/商品ID预校验去重。

  1. 原理
    • 布隆过滤器是一个bit向量或者说bit数组,所有bit初始值为0。

结构

  • 布隆过滤器离不开哈希函数,它有如下特点

    • 输入值域无限;输出值域固定;
    • 相同输入,哈希结果一定相同;
    • 不同输入,哈希结果可能相同(哈希冲突);
    • 哈希结果尽量均匀分布,减少聚集。
  • 如果我们要映射一个值到布隆过滤器中,需要使用多个不同的哈希函数生成多个哈希值,并对每个生成的哈希值指向的bit位设为1,例如针对值“baidu”和三个不同的哈希函数分别生成了哈希值1、4、7,则上图转变为:

百度

  • 再存一个值“tencent”,假设三个不同的哈希函数得到的哈希值分别为3、4、8,图继续变为:

腾讯

  • 如图,4这个bit位由于两个值的哈希函数都返回了这个bit位,因此它被覆盖了。
  • 当需要查询“dianping”这个值是否存在,假设三个哈希函数分别得到哈希值1、5、8。结果发现5这个bit位上的值为0,说明没有任何一个值映射到这个bit位上,因此可以很确定地说“dianping”这个值不存在。
  • 当需要查询“baidu”这个值是否存在,那么三个哈希函数肯定会拿到1、4、7三个值。然后发现这三个bit位上的值均为1,那么可以说“baidu”这个值可能存在,即哈希冲突的问题。
  1. 适用场景

    • 爬虫URL去重:避免重复抓取相同链接;
    • 缓存穿透防护(Redis最常用场景):拦截不存在的key,防止大量空请求穿透到数据库;
    • 黑名单校验、手机号/优惠券ID去重;
  2. ❗不适合场景

    需要精准判断元素是否存在(不能容忍误判);
    需要频繁删除元素(普通布隆无法删除);
    元素数量无法预估,持续无限增长(bit数组会被填满)。

二、使用

注意:原生Redis内核没有内置布隆过滤器,两种实现方案:

  1. 方案1:Redis原生Bitmap手动实现布隆过滤器
    利用SETBIT / GETBIT命令,自己在业务代码编写多个哈希函数,计算bit位置,操作bitmap。
    优点:不需要安装Redis模块,任意版本Redis都能用;
    缺点:
  • 需要自己实现哈希算法、计算bit长度,维护成本高
  • 没有内置误判率计算,需要自行估算
  • 不支持批量操作,容易写bug

一般生产很少手写,优先RedisBloom模块。

  1. 方案2:RedisBloom模块(推荐)
    Redis 4.0+支持加载模块,RedisBloom提供完整布隆过滤器命令,云厂商托管Redis(阿里云/腾讯云)大多已经预装RedisBloom。

三、全置为1的问题

  1. 随着不断插入元素,bit 数组中 0 的 bit 位会越来越少:

    • 在还没有全部变成 1 之前,误判率就会持续上升,业务上已经不可用,不是等到全部置 1 才失效;
    • 一旦 bit 数组全部置为 1:任何元素查询,所有哈希对应的 bit 都是 1,布隆过滤器100% 返回 “可能存在”,过滤器完全失效;
    • 后果:缓存穿透防护失效,无效请求全部打到数据库。
  2. 解决办法

    • 创建时预留容量余量:BF.RESERVE 设置预估数量,实际插入量不要超过预设值;
    • 分片布隆(可扩展布隆):代码维护多个独立布隆分片,新增数据写入新分片;查询时遍历所有分片;旧分片可以直接删除,解决容量上限问题
      • RedisBloom 本身不自带分片,需要业务层实现;
    • 定时重建布隆过滤器:定时从DB全量同步合法ID,生成新布隆,切换引用,销毁旧过滤器;
      • 适合数据相对稳定场景;
    • 监控:监控布隆插入数量,接近预设阈值告警。

四、常见误区

  1. ❌ 布隆过滤器可以判断元素一定存在
    ✅ 只能判断元素一定不存在;返回存在只是大概率。
  2. ❌ Redis 原生自带布隆过滤器
    ✅ 原生 Redis 没有,需要 RedisBloom 模块;Bitmap 只是底层 bit 结构,可以手动实现布隆。
  3. ❌ 布隆可以删除元素
    ✅ 普通布隆不能删除;删除会影响其他元素。
  4. ❌ 元素数量超出预设值只是一点点,没关系
    ✅ 超出预设容量后,误判率会快速恶化。

五、参考

  1. 参考一
  2. 参考二