布隆过滤器必须在请求进入redis前执行判断,正确顺序为接收请求→参数校验→bf.exists校验→缓存查询;预热数据格式须与查询完全一致,且需配合空值缓存与前端参数拦截。

布隆过滤器必须在请求进入 Redis 之前执行判断,否则无效请求已打到缓存甚至数据库——这不是配置问题,是调用位置错误导致的防御失效。
BF.EXISTS 必须放在 cache.get() 之前
ThinkPHP 中常见错误是把 BF.EXISTS 放在 Cache::get() 之后,比如先查缓存未命中、再查 BF、最后查 DB。这等于让所有非法 key 都走完一次 Redis 网络往返,完全失去前置拦截意义。
- ✅ 正确顺序:接收请求 → 校验参数(如
id > 0 && ctype_digit($id))→$redis->executeRaw(['BF.EXISTS', 'bf:user', "user:{$id}"])→ 不存在则直接返回 404 - ❌ 错误顺序:
Cache::get("user:{$id}")未命中 → 再执行BF.EXISTS→ 查 DB - TP8.0 没有内置 BF 中间件,需手动在全局中间件或 BaseController 构造函数中插入该逻辑,不能依赖模型层或 Service 层
RedisBloom 模块必须提前部署且版本 ≥ 2.4
BF.RESERVE 和 BF.ADD 是 RedisBloom 模块提供的原生命令,不是 PHP 自实现。如果 redis-cli INFO modules | grep bloom 没输出或 version BF.* 命令都会报错 (error) ERR unknown command `BF.RESERVE`。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 必须由运维在 Redis 实例启动时加载
redisbloom.so,不支持运行时MODULE LOAD(某些云 Redis 不开放权限) - 本地开发用 Docker 可参考:
docker run -p 6379:6379 --rm redislabs/rebloom:2.4 - TP8.0 使用
Predis或phpredis均可调用,但别用Cache::store('redis')->getRedis()获取实例后直接->bfExists()—— 它不识别自定义命令,得用executeRaw()
预热数据格式必须和查询时完全一致
布隆过滤器不自动类型转换。你往里面加 "1001",查询时传 1001(int)或 "user:1001" 都会判为“不存在”。
- 缓存 key 是
"user:{$id}",预热时就必须用BF.ADD bf:user "user:1001",而不是只加"1001" - 全量预热建议在迁移脚本或命令行任务中执行:
SELECT CONCAT("user:", id) FROM user WHERE status = 1,拼成数组后批量BF.ADD - 增量同步:每次新增用户后,立即执行
$redis->executeRaw(['BF.ADD', 'bf:user', "user:{$newId}"]);删除用户无法从 BF 删除,只能定期重建或容忍短期误判
空值缓存要配合 BF 且带扰动 TTL
BF 能拦住“数据库里绝对没有”的 ID,但拦不住“刚删掉的用户”或“格式合法但业务已注销”的情况。这时空值缓存是第二道防线,但不能无脑塞 SET user:999999 "" EX 300。
- 只对高频重复无效请求缓存空值:同一
user_id在 60 秒内被请求 ≥3 次才触发setex("user:{$id}", 300 + random_int(0, 60), "__EMPTY__") - 业务代码中必须显式检查空值标记:
if ($cacheVal === '__EMPTY__') { return null; },不能当成真实数据反序列化 - 前端传参明显越界(如
id=0、id=-123、id="abc")应在中间件里用正则/^[1-9]\d{0,15}$/直接拦截,不进 BF 流程
最容易被忽略的是 BF 初始化时机和 key 格式对齐——预热漏掉一个 "user:1001",这个 ID 就永远被误判为不存在;而误判率设太高(如 0.1),100 万用户下可能每天多穿透几千次,压测时根本看不出来。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










