直接说结论:用 Redis 替代 PHP 默认的文件缓存,响应速度能从百毫秒级别压到几毫秒。前提是——连接不乱建、键不瞎设、过期策略不能硬写。下面几个关键点,每一条都可能让缓存性能翻车,或者反过来,让系统跑得飞起。
怎么连 Redis 才不拖慢请求
每次请求都来一句 new Redis() + connect(),等于每回都走一遍 TCP 握手加认证,实测下来至少增加 20–50ms 延迟。用 pconnect() 是更稳妥的选择,它复用底层连接,脚本结束才断开,能省下大量开销。
pconnect()的第三个参数是超时秒数,设太小(比如 1)容易被误杀,建议 30 秒或更高- 如果跑在 Swoole、Workerman 这类常驻进程里,
connect()一次就够了,后续直接复用实例 - 别忘了
auth()和select(),否则可能连错库或被密码拦截。常见的报错信息是Connection refused或NOAUTH Authentication required
setex 和 set 的 TTL 参数到底怎么填
setex() 看起来省事,但固定 TTL 容易引发缓存雪崩。比如所有用户资料都设 3600 秒过期,整点一到,大量请求同时穿透,数据库直接被打趴。
- 用
set()配合EX选项更灵活:$redis->set('user:1001', json_encode($data), ['EX' => 3600 + rand(0, 300)]),加一点随机偏移就能有效分散过期时间 - 数值型缓存(如计数器)可以设永不过期,靠业务逻辑主动清理;字符串类缓存必须带 TTL
- 超过 24 小时的 TTL,Redis 内部会转成绝对时间戳,但 PHP 层无需关心,直接填秒数即可
为什么 get() 返回 false 却不是缓存没命中
get() 返回 false 有三种可能:键不存在、键存在但值就是 false 字符串、连接中断。直接拿 === false 判断会误伤真实数据,这是很多新手踩过的坑。
- 先
exists('key')检查键是否存在,再get()取值,虽然多一次往返,但逻辑清晰 - 更轻量的做法:统一用
json_encode()存,取出来用json_decode($v, true),空值自然为null,不会和false混淆 - 如果用了压缩(如
zlib),get()返回的是二进制数据,直接 echo 会乱码,得先gzuncompress()
Hash 和 String 什么时候该选哪个
存整个用户对象用 String 最简单,但改其中某个字段(比如头像 URL)就得全量覆盖。这时候 hSet() 就显出优势了——只更新需要的字段,其他不变。
- 字段稳定、读写粒度粗 → 用
String+setex() - 字段多变、常局部更新(如用户积分、最后登录时间)→ 用
Hash,hGetAll()一次性取全,hIncrBy()原子增减 - 别把
Hash当数据库用:字段超过 50 个、单个值超 1KB,性能会明显下降

真正卡住性能的,往往不是 Redis 本身,而是键名设计太随意(比如带 session_id 的动态键导致无法复用)、没做连接异常兜底(try/catch 漏掉 RedisException)、或者缓存与数据库更新顺序错乱。这些点不提前压住,加再多节点也白搭。从数据来看,做好以上几项,缓存命中率轻松拉到 95% 以上,响应时间稳定在个位数毫秒级。