Redis连接失败主因是协议与地址配置不当,需用Predis容错、显式设超时、正确处理auth;缓存穿透应空值缓存+布隆过滤;setex原子安全,pipeline慎用;key命名须统一函数生成,更新前删缓存。

Redis 连接失败或超时,new Redis() 报错
PHP 连 Redis 最常见的卡点不是密码或端口,而是默认用 tcp 协议连本地 127.0.0.1:6379,但很多 Docker 环境或云 Redis 实际走的是 redis:// URL 或需要 auth 显式传参。直接 new 会抛出 Connection refused 或卡住几秒后 timeout。
- 用
Predis\Client比原生Redis扩展更容错,尤其处理 URL、密码、连接池参数更直观 - 必须显式设置超时:
['timeout' => 1.5, 'read_write_timeout' => 1.0],否则默认是无限等待 - Docker 内 PHP 连宿主机 Redis 别写
127.0.0.1,改用宿主网关(如172.17.0.1)或host.docker.internal - 如果 Redis 开了
requirepass,auth参数不能塞在 URL 里(redis://:pwd@...),某些旧版 Predis 会忽略,得单独传'password' => 'xxx'
缓存穿透:查不到的 key 频繁打到数据库
用户反复请求 user_id=9999999 这种根本不存在的 ID,Redis 没命中,每次直连 MySQL,DB 压力飙升。这不是 Redis 配置问题,是业务层没兜底。
- 对空结果也缓存,但 TTL 要短(比如
60秒),避免脏数据长期滞留;值可以设成null或"MISS"字符串 - 加一层布隆过滤器(Bloom Filter)前置判断——适合写少读多、key 空间固定的场景,比如用户 ID 全量预热后做存在性校验
- 别在
SELECT ... WHERE id = ?后直接SET,先GET一次,命中就跳过 DB;没命中再查 DB,查不到就SETEX key 60 "MISS" - 注意:PHP 的
json_encode(null)是"null"字符串,不是 JSON null,反序列化时要统一处理
setex 和 set + ex 参数行为不一致
看起来都是设带过期的 key,但底层协议和原子性有差别。用错会导致缓存写入成功但没过期,或者并发时被覆盖。
-
$redis->setex($key, $ttl, $value)是原子命令,安全;而$redis->set($key, $value, ['ex' => $ttl])在 PHP Redis 扩展 v5.3.2+ 才真正支持数组选项,低版本会静默忽略ex - 如果用
Predis,set($key, $value, 'ex', $ttl)是推荐写法,兼容性好;别写成set($key, $value, ['ex' => $ttl]),老版本 Predis 会报参数错误 - 批量操作慎用
pipeline包setex:如果中间某条失败,整个 pipeline 不回滚,得自己捕获异常并清理已写入的 key
数据库更新后,缓存没删或删错了 key
用户改了昵称,MySQL 更新成功,但 Redis 里还是旧昵称——不是没删缓存,是删的 key 和读的 key 对不上,比如读用 user:123,删却写了 user_123。
立即学习“PHP免费学习笔记(深入)”;
- 所有缓存 key 的生成逻辑必须抽成函数,比如
cacheKey('user', $id),全局只定义一次,杜绝硬编码字符串 - 更新数据库前先删缓存(Cache-Aside 的 delete-then-update),避免更新瞬间出现短暂脏读;但要注意:删完 DB 更新失败,缓存就空了,下次读会重建,可接受
- 涉及关联数据(如用户+订单列表),别只删
user:123,还要删user_orders:123,最好用keys user_orders:123*扫描删,但线上禁用——改用业务层维护二级索引 key,比如user:123:related_keys存一个数组,更新时一起删
最麻烦的永远不是连上 Redis,而是缓存和数据库之间那几毫秒的时序、key 命名的随意性、以及空值处理的遗忘。这些地方一松懈,监控曲线就立刻露馅。











