Redis缓存被击穿,使用布隆过滤器加互斥锁双保险
【摘要】 热点 Key 过期瞬间大量请求直穿数据库,用布隆过滤器挡住不存在的 Key,互斥锁保证只有一个请求查 DB,附 Go 代码实现。
一、击穿和雪崩别搞混
先理清下概念,常见的三种缓存问题如下:
| 问题 | 触发条件 | 影响范围 |
|---|---|---|
| 缓存击穿 | 单个热点 Key 过期 | 大量请求打到 DB |
| 缓存雪崩 | 大批 Key 同时过期 | DB 被压垮 |
| 缓存穿透 | 查询不存在的 Key | 每次都查 DB |
主要讲解下击穿,还有穿透的防护

二、两道防线
单靠一种手段不够稳,我用了两道防线叠着来:
第一道:布隆过滤器——在请求到 Redis 之前先过一遍,Key 不存在的直接返回,根本不让它往下走。这样既防了穿透,又减少了 Redis 的无效查询。
第二道:互斥锁——缓存未命中时,用 Redis 的 SETNX 加一把锁,拿到锁的那个请求去查 DB 并回写缓存,拿不到锁的等一下再重试读缓存。这样保证同一时间只有一个请求打到 DB。

三、代码实现
这里用Go和go-redis写个简单的示例:
package main
import (
"context"
"time"
"github.com/redis/go-redis/v9"
"github.com/bits-and-blooms/bloom/v3"
)
type CacheGuard struct {
rdb *redis.Client
bf *bloom.BloomFilter
}
// Get 先过布隆过滤器,再查缓存,miss 时加互斥锁查 DB
func (cg *CacheGuard) Get(ctx context.Context, key string) (string, error) {
// 第一道:布隆过滤器
if !cg.bf.Test([]byte(key)) {
return "", nil // Key 不存在,直接返回
}
// 查 Redis
val, err := cg.rdb.Get(ctx, key).Result()
if err == nil {
return val, nil // 缓存命中
}
// 第二道:互斥锁
lockKey := "lock:" + key
locked, err := cg.rdb.SetNX(ctx, lockKey, 1, 3*time.Second).Result()
if err != nil {
return "", err
}
if locked {
defer cg.rdb.Del(ctx, lockKey)
// 查 DB
val := queryFromDB(key)
// 回写缓存,加随机过期时间防雪崩
ttl := 30*time.Minute + time.Duration(randInt(0, 300))*time.Second
cg.rdb.Set(ctx, key, val, ttl)
return val, nil
}
// 没拿到锁,等一下重试
time.Sleep(50 * time.Millisecond)
return cg.Get(ctx, key)
}
里面有几个细节:
- 布隆过滤器用
bits-and-blooms/bloom库,启动时把 DB 里已有的 Key 全灌进去 - 互斥锁用
SETNX实现,加 3 秒超时防止拿锁的请求挂了导致死锁 - 回写缓存时 TTL 加了随机偏移,避免大量 Key 在同一时刻过期引发雪崩
- 没拿到锁的请求 sleep 50ms 后重试,这时缓存大概率已经回写好了
四、布隆过滤器怎么维护
布隆过滤器有个特点:能加 Key 不能删 Key。如果删除了某个 Key,布隆过滤器里还留着标记,会导致误判。
两种解法:
- 定期重建:每小时用 DB 全量 Key 重建一次布隆过滤器,简单粗暴,大部分场景够用
- Counting Bloom Filter:把每个 bit 换成计数器,支持删除,但内存翻几倍,数据量大不划算
五、注意监控
上线后盯几个指标:
- Redis 的
rejected_connections:如果互斥锁等待太多,说明热点 Key 频繁失效,考虑加永不过期 + 异步刷新策略 - DB 的
threads_running:正常应该是个位数,突然飙升说明防线没兜住 - 布隆过滤器的误判率:理论上 1% 左右,实际跑起来基本感知不到
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)