当前位置:首页 >  站长 >  建站经验 >  正文

Redis缓存穿透打垮数据库?空值缓存加布隆过滤器双保险

 2026-08-29 18:52  来源: 互联网   我来投稿 撤稿纠错

  一键部署OpenClaw

缓存穿透的典型场景:有人拿脚本扫你的站,每次请求一个根本不存在的ID,比如 /goods.php?id=99999999。Redis里查不到,请求全落到MySQL,而MySQL也查不到,什么都不缓存。下一波请求还是这个流程,数据库白挨打,缓存形同虚设。

跟缓存击穿(某个热key过期)不一样,穿透的点是“查询结果为空”这种结果默认不进缓存。解决方案也就两个思路:要么把“空”也缓存起来,要么在缓存前面挡一道,让不存在的key根本到不了数据库。

// 方案一:空值缓存,短过期时间
$key = 'goods:' . $id;
$data = $redis->get($key);
if ($data === 'NULL_MARK') {
exit('商品不存在'); // 命中空值标记,直接返回
}
if ($data === false) {
$row = $db->query("SELECT * FROM goods WHERE id=?", [$id]);
if (!$row) {
$redis->setex($key, 60, 'NULL_MARK'); // 空 };

空值缓存的过期时间别设长,30到60秒够了。设太长有个副作用:后台刚补录了这个商品,前台一分钟内还是“不存在”,运营会以为出bug了。真遇到这种情况,录入成功后顺手删一次key就行。

第二层保险是布隆过滤器。原理不用抠细节,只要知道:它能判断“这个key一定不存在”或“可能存在”,误判率可以调。把全量商品ID预热进布隆过滤器,请求先问它一声,一定不存在的直接拒绝,连Redis都不用查。

# Redis 4.0+ 自带布隆过滤器模块(RedisBloom)
# 插入全量商品ID
BF.ADD goods_filter 10001
BF.ADD goods_filter 10002
# 查询:0=一定不存在 1=可能存在
BF.EXISTS goods_filter 99999999

验证效果很直观:压测工具拿不存在的ID打接口,开穿透防护前数据库QPS飙到几千,开了之后Redis命中空值标记,数据库QPS归零。看一眼redis-cli的info stats里keyspace_misses是否还在疯涨,就知道防护有没有生效。

个人建议小站先用空值缓存就够了,布隆过滤器那套适合数据量大、攻击面广的站。另外别忘了一个更省事的兜底:对参数做合法性校验,ID不是数字、超出合理范围的直接404,很多“穿透攻击”其实就是拿随机字符串扫的,一层is_numeric就能挡掉大半。

数据来源:Redis官方文档

申请创业报道,分享创业好点子。点击此处,共同探讨创业新机遇!

相关标签
php教程

相关文章

热门排行

信息推荐