vault backup: 2026-05-25 23:50:33
This commit is contained in:
@@ -42,7 +42,25 @@ graph LR
|
||||
|
||||
### 方案 A:RedisBloom 模块(服务端)
|
||||
|
||||
RedisBloom 是 Redis 官方模块,通过 `BF.ADD` / `BF.EXISTS` 命令直接操作。
|
||||
RedisBloom 是 Redis 官方模块,**默认不随 Redis 一起安装**,需要单独编译或通过 Docker 加载:
|
||||
|
||||
```bash
|
||||
# Docker 方式(推荐)
|
||||
docker run -p 6379:6379 redis/redis-stack-server # 内置 RedisBloom
|
||||
```
|
||||
|
||||
核心命令:
|
||||
|
||||
| 命令 | 说明 |
|
||||
|------|------|
|
||||
| `BF.RESERVE key error_rate capacity` | 创建自定义布隆过滤器(生产环境推荐) |
|
||||
| `BF.ADD key item` | 添加元素(自动创建默认参数的过滤器) |
|
||||
| `BF.EXISTS key item` | 查询元素,返回 1=可能存在 / 0=一定不存在 |
|
||||
| `BF.MADD key item1 item2 ...` | 批量添加 |
|
||||
| `BF.MEXISTS key item1 item2 ...` | 批量查询 |
|
||||
|
||||
> [!tip] 生产环境务必用 `BF.RESERVE` 预创建
|
||||
> `BF.ADD` 首次调用时会以默认参数自动创建过滤器(容量约 100,误判率 0.01),数据量稍大就会急剧膨胀误判率。正确做法是先 `BF.RESERVE user_filter 0.0001 1000000` 显式声明参数。
|
||||
|
||||
```go
|
||||
// go-redis 调用 RedisBloom
|
||||
@@ -138,7 +156,9 @@ func (s *BloomCacheService) GetUser(ctx context.Context, userID string) (*User,
|
||||
return nil, nil // 缓存的空值
|
||||
}
|
||||
var user User
|
||||
json.Unmarshal(data, &user)
|
||||
if err := json.Unmarshal(data, &user); err != nil {
|
||||
return nil, err // JSON 反序列化失败
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
@@ -220,7 +240,24 @@ func calcBloomParams(n int, p float64) (m int, k int) {
|
||||
|
||||
### 6.1 不支持删除
|
||||
|
||||
标准布隆过滤器不支持删除——将某位从 1 置为 0 可能影响其他元素判断。解决方案是**计数布隆过滤器(Counting Bloom Filter)**,用计数器替代 1 bit,删除时计数器减 1。RedisBloom 的 Cuckoo Filter(`CF.ADD` / `CF.EXISTS`)也原生支持删除。
|
||||
标准布隆过滤器不支持删除——将某位从 1 置为 0 可能影响其他元素判断。两种解决方案:
|
||||
|
||||
| 方案 | 原理 | 优点 | 缺点 |
|
||||
|------|------|------|------|
|
||||
| **计数布隆过滤器** | 用计数器替代 1 bit,删除时减 1 | 兼容标准布隆过滤器思路 | 内存开销增大 3-4 倍 |
|
||||
| **Cuckoo Filter** | 基于 cuckoo hashing,直接存储元素指纹 | 支持删除、查询更快、空间更优 | 容量接近满时插入可能失败 |
|
||||
|
||||
RedisBloom 中 Cuckoo Filter 的命令:
|
||||
|
||||
```bash
|
||||
CF.RESERVE key capacity # 创建
|
||||
CF.ADD key item # 添加
|
||||
CF.EXISTS key item # 查询
|
||||
CF.DEL key item # 删除(布隆过滤器做不到)
|
||||
```
|
||||
|
||||
> [!tip] 何时用 Cuckoo Filter?
|
||||
> 如果你的场景**需要删除过期元素**(比如用户注销后移除 ID),优先用 Cuckoo Filter。如果只做"只增不查删"的穿透防护,标准布隆过滤器更简单高效。
|
||||
|
||||
### 6.2 需要预加载
|
||||
|
||||
@@ -229,6 +266,13 @@ func calcBloomParams(n int, p float64) (m int, k int) {
|
||||
> [!question] 如果新增了数据但忘记更新布隆过滤器会怎样?
|
||||
> 新增的 key 在布隆过滤器中查询会返回"不存在",导致合法请求被误拦截。这比缓存穿透更严重——用户明明有数据却查不到。所以务必确保新增数据时同步 `BF.ADD` 或 `filter.AddString()`。
|
||||
|
||||
> [!warning] Go-side 过滤器的重启问题
|
||||
> Go 内存中的布隆过滤器在进程重启后**完全丢失**。两种应对策略:
|
||||
> 1. **启动时重建**:从 DB 全量加载 ID 重新构建(数据量大时启动慢,可用 goroutine 并行加载)
|
||||
> 2. **持久化 bit 数组**:将 bit 数组序列化到 Redis 或文件,启动时反序列化恢复(快但需要额外维护一致性)
|
||||
>
|
||||
> 如果重建成本不可接受,优先考虑 RedisBloom——数据随 Redis 持久化,应用重启无感知。
|
||||
|
||||
### 6.3 误判率随使用上升
|
||||
|
||||
实际元素数量远超预估值 `n` 时,误判率会显著上升。建议预留 20%-30% 余量,监控实际元素数量,必要时重建过滤器。
|
||||
|
||||
Reference in New Issue
Block a user