Redis扩展必须安装并启用才能使用new Redis(),否则报Class 'Redis' not found;predis是纯PHP客户端但性能较差;set/get默认序列化导致null值歧义;pipeline提升吞吐量,multi保证简单事务,复杂场景需Lua或应用层锁。

Redis 扩展是否已安装并启用
PHP 操作 Redis 前,必须确认 redis 扩展已编译进 PHP 或通过 extension=redis.so(Linux/macOS)或 extension=php_redis.dll(Windows)启用。仅装了 phpredis 包但没启用扩展,调用 new Redis() 会直接报错 Class 'Redis' not found。
验证方式很简单:
php -m | grep redis
或者在 Web 环境中运行:
- 返回
true才能继续;返回false就得先配扩展,不是装composer require predis/predis就能替代的 -
predis是纯 PHP 客户端,不依赖扩展,但性能和连接复用能力弱于原生redis扩展 - PHP 8.0+ 用户注意:旧版
phpredis(5.3.7+ 版本
new Redis() 连接时的超时与重试控制
默认 new Redis() 不带参数时不会自动连接,首次调用命令(如 set)才触发连接,且默认超时是 0(无限等待),线上环境极易卡死。必须显式调用 connect() 并设好超时。
立即学习“PHP免费学习笔记(深入)”;
-
connect($host, $port, $timeout, $retry_interval, $read_timeout)中,$timeout是连接建立超时(秒),$read_timeout是读响应超时(秒),两者都应设为1.0或更小 -
$retry_interval在连接失败后重试前等待毫秒数,设为100可避免密集轮询 - 不要用
pconnect()在 CLI 脚本里——它不会真正复用连接,反而可能残留 socket 导致Too many open files
connect('127.0.0.1', 6379, 1.0, 100, 1.0);
} catch (RedisException $e) {
// 注意:RedisException 不是 RuntimeException,需单独捕获
error_log('Redis connect failed: ' . $e->getMessage());
exit(1);
}
?>
set / get 的序列化行为与 null 值陷阱
set() 默认对非字符串值做 serialize(),get() 会自动 unserialize()。这看似方便,实则埋下隐患:
- 存
null时,get()返回false(不是null),且无法区分“键不存在”和“存了 null” - 开启
redis.serializer = php(php.ini)会影响所有实例,不推荐;应在代码里统一用setex()+json_encode()控制格式 - 如果只存字符串,显式转成字符串再 set,避免意外序列化:
$redis->set('key', (string)$value)
set('user:id:123', json_encode(['name' => 'Alice', 'age' => 30]));
$data = json_decode($redis->get('user:id:123'), true);
// 比直接 set(array) + get() 更可控、无反序列化风险
?>
pipeline 和 multi 的适用边界
批量操作别盲目上 multi(Redis::PIPELINE)。它只是把命令攒起来发一次,不保证原子性;而 multi(Redis::MULTI) 才是事务,但 Redis 的事务不支持回滚,出错只报错不中断。
- 纯粹提升吞吐量(比如批量写日志)、无需一致性校验 → 用
pipeline - 需要多个 key 同时成功/失败(如扣库存+写订单),且逻辑简单 → 用
multi+exec,但得自己检查exec返回值是否全为非null -
watch()配合multi可实现乐观锁,但 watch 的 key 被改就会使exec返回false,这点常被忽略
真正难处理的是跨库、跨实例、含条件判断的复合操作——这时候就得退回到应用层加锁或用 Lua 脚本,而不是硬塞进 pipeline。











