webman中必须用webman/redis扩展管理连接池,禁用new redis()或redis_connect(),否则高并发下连接爆炸、time_wait堆积、redis拒绝连接。

Webman 里直接 new Redis() 或用原生 redis_connect(),高并发下必然连接爆炸、TIME_WAIT 堆积、Redis 拒绝新连接——这不是缓存,是自毁。
必须用 webman/redis 扩展接管连接池
Webman 的 Worker 进程常驻内存,每个请求都 new 一次 Redis 实例,等于每秒创建数百个 TCP 连接。系统扛不住,Redis 也扛不住。
- 装扩展:
composer require webman/redis - 配连接池(
config/redis.php):'pool' => ['min_connections' => 2, 'max_connections' => 20],别设成 100,够用就行 - 业务中统一走
Redis::get()/Redis::setex(),底层自动取放连接,不操心释放 - 禁止在
onWorkerStart里new Redis()后赋值给全局变量,多进程间会共享连接句柄,序列化失败或写错库
Key 必须带业务域 + 参数签名 + 版本号
写死 Cache::set('user_list', $data) 看似简单,实则埋雷:改个分页逻辑、换种查询条件,缓存就永远不更新;多个环境共用 Redis,key 冲突直接串数据。
- 正确结构示例:
user:list:type_'.$type.':page_'.md5(json_encode([$page,$size])).':v2 - 用
json_encode()而非serialize()做参数哈希,避免 PHP 升级导致 hash 不一致 - 版本号(如
:v2)比批量del user:list*更可控,上线即生效,无延迟 - 敏感字段(如用户 ID、手机号)不要明文拼进 key,防缓存探测和越权访问
请求级缓存 + 分布式锁防穿透,不能只靠 Redis 过期
热门接口(如商品详情、排行榜)缓存失效瞬间,上百请求同时打到数据库,就是雪崩。Redis 单层过期机制完全不够用。
- 第一层:单次请求内用
context()->get('cache')或静态变量暂存,避免同个请求重复查同个 key - 第二层:Redis 缓存,跨请求复用
- 穿透防护:查库前先用
Redis::setnx($lockKey, 1, 10)尝试加锁,成功才查库并回填缓存;失败则usleep(50000)后重试,别硬刚 - 别用
SETNX + EXPIRE两步操作,存在竞态,必须用原子命令SET $key $val EX 10 NX
延迟双删不是可选项,是强约束
更新数据库后立刻删缓存,看似合理,但若删缓存成功、DB 更新失败,下次读到的就是脏数据;更糟的是,更新 DB 和删缓存之间有并发读,极易命中旧缓存。
- 标准流程:删缓存 → 更新 DB → 延迟(如 500ms)→ 再删缓存
- 延迟用
Redis::pexpire()或起异步任务,别阻塞主流程 - 延迟时间要大于主从同步最大延迟,宝塔部署时注意 Redis 主从复制 lag
- 如果业务允许最终一致性,可用「更新 DB 后主动刷新缓存」替代双删,但需确保刷新失败有告警
Webman 的常驻内存优势,只有在连接复用、key 可控、穿透有防、更新有兜底的前提下,才能真正转化成毫秒级响应。漏掉其中任一环,缓存就只是个耗资源的摆设。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











