主题切换
布隆过滤器
一、底层基础:Bitmap位图
Bitmap 本质是二进制位数组,数组每个位置仅存储 0 或 1,仅占用 1bit 空间,内存利用率极高。
- 0:对应下标位置无数据
- 1:对应下标位置已标记存在数据
二、元素存入规则
以存入 id=1 为例:
- 对同一个元素,通过多个不同哈希函数计算出多个位图下标;
- 将所有计算出的下标位置的值统一改为 1。 一条数据会占用多个 bit 位,并非只占用单个位置。
三、元素查询规则
- 判断不存在:只要任意一个哈希对应下标为 0,数据一定不存在,结果百分百准确。
- 判断存在:所有哈希对应下标均为 1,数据大概率存在,存在误判可能。
误判原因
不同元素经过哈希计算后,下标发生碰撞,对应位置都被标记为 1。此时查询不存在的元素,也会判定为存在。 核心特性:只会误判存在,绝不会误判不存在。
四、优缺点
优点
- 采用 bit 位存储,内存占用极小,可承载海量数据。
- 基于哈希与位运算实现,查询、写入速度极快。
缺点
- 无法直接删除数据:单个 bit 位会被多个元素共用,删除一个元素会影响其他数据标记。
- 存在小概率哈希碰撞,出现误判。
五、Redis 业务应用:解决缓存穿透
- 项目启动时,将数据库中所有合法数据 ID 预先加载到布隆过滤器。
- 接收用户请求携带 ID:
- 过滤器判定数据不存在,直接拦截请求,不再访问 Redis 和 MySQL。
- 过滤器判定数据存在,正常走查询流程:先查 Redis,缓存未命中再查询数据库。
六、两种落地实现方案
一、Guava 布隆过滤器(单机版)
1. 特点
- 本地内存实现,数据存储在 JVM 内存中,不依赖第三方中间件。
- 不支持集群共享,集群部署时各实例数据相互独立,无法保证一致性;项目重启后数据丢失。
- 适用场景:单体项目、数据量较小的业务。
2. 优点
开箱即用,依托 Guava 内置 API,无需额外部署组件。
二、Redisson 布隆过滤器(分布式版,生产主流)
1. 特点
- 基于 Redis Bitmap 实现,过滤器数据统一存储在 Redis,集群内所有服务实例共享同一份数据。
- 项目重启、多实例部署均不会丢失数据,完美适配微服务分布式架构。
2. 适用场景
分布式微服务项目,是线上防止缓存穿透的首选方案。
三、两者核心对比
| 方案 | 存储位置 | 分布式支持 | 优缺点 |
|---|---|---|---|
| Guava | JVM本地内存 | 不支持集群 | 使用简单,集群环境下失效 |
| Redisson | Redis位图 | 支持全服务共享 | 分布式标准实现,依赖Redis |
四、业务选型
- 单体项目 → 选用 Guava 布隆过滤器
- 微服务/分布式项目 → 选用 Redisson 布隆过滤器
七、面试高频问题解析
问:简述布隆过滤器底层原理与查询特点?
答: 底层基于 Bitmap 二进制位数组,通过多个哈希函数对元素计算下标并标记为1。查询时,只要有一个下标为0就判定数据不存在;全部为1则判定存在。该结构只会出现“误判存在”,不会误判不存在。
问:布隆过滤器为什么不能删除数据?
答: 多个元素会共用同一个 bit 位,直接将位置置0,会导致其他正常数据被误删除,因此原生布隆过滤器不支持删除操作。
问:布隆过滤器在Redis场景下主要解决什么问题?
答: 主要用来解决缓存穿透。将合法数据ID提前存入过滤器,非法请求直接拦截,避免大量空请求穿透到数据库,保护MySQL。
问:Guava和Redisson实现的布隆过滤器有什么区别,如何选型?
答: Guava是本地内存实现,仅适用于单体项目,集群无法共享数据;Redisson基于Redis实现,支持分布式集群。单体项目选Guava,微服务分布式项目优先使用Redisson。