本文目录导读:

在PHP项目中连接和操作Redis集群,主要有两种主流方案:PhpRedis扩展 和 Predis库。
以下是详细的连接配置、操作示例以及关键的注意事项。
使用 PhpRedis 扩展(推荐,性能最高)
这是C语言编写的PHP扩展,性能最好,功能最全。
安装扩展
- Linux/macOS:
pecl install redis - Windows:在 PECL官网 下载对应的DLL文件。
- 启用扩展:在
php.ini中添加extension=redis
连接集群代码
RedisCluster 类会自动处理节点的发现、槽位映射、MOVED/ASK重定向以及节点故障转移。
<?php
// Redis集群节点列表,只需要提供部分(建议提供多个)种子节点即可
$seeds = [
'192.168.1.10:6379',
'192.168.1.11:6379',
'192.168.1.12:6379',
];
// 创建集群对象
// 参数1: null 表示自动从种子节点中获取集群信息
// 参数2: 节点配置数组
// 参数3: 超时时间
// 参数4: 读写超时时间
$cluster = new RedisCluster(
null,
$seeds,
1.5, // 连接超时(秒)
1.5, // 读超时
false // 是否持久化连接
);
// 设置认证密码(如果集群开启了requirepass,所有节点密码必须一致)
$cluster->auth('your_password');
// ====== 基本操作 ======
$cluster->set('my_key', 'Hello Cluster');
$value = $cluster->get('my_key');
echo $value; // 输出: Hello Cluster
// ====== 批量操作(注意:跨节点的MGET性能较差) ======
$cluster->mSet(['key1' => 'val1', 'key2' => 'val2']);
$values = $cluster->mGet(['key1', 'key2']);
// ====== 使用哈希(常用) ======
$cluster->hSet('user:1001', 'name', 'Alice');
$cluster->hSet('user:1001', 'age', 30);
$info = $cluster->hGetAll('user:1001');
print_r($info);
// ====== 设置过期时间 ======
$cluster->expire('my_key', 3600); // 1小时过期
// 或者在set时直接加上过期时间
$cluster->set('tmp_key', 'data', ['ex' => 60, 'nx']); // 不存在时设置,60秒过期
// ====== 执行lua脚本 ======
$script = 'return redis.call("get", KEYS[1])';
$result = $cluster->eval($script, ['my_key'], 1); // 注意参数格式
重要特性与坑点
- MGET/MSET跨节点问题:如果键分布在不同的节点上,
mget会分批次请求,建议使用hash tag确保相关键在同一个节点上(如user:1001:name,user:1001:age使用花括号{user1001}:name)。 - Pipeline:支持,但需要指定同一个节点发送命令。
- 事务(MULTI/EXEC):仅支持键在同一个slot的事务,跨节点事务直接报错或无法正常提交。
使用 Predis 库(纯PHP,兼容性强)
无需安装额外扩展,通过Composer引入,适合共享主机或不想安装PhpRedis的场景。
安装
composer require predis/predis
连接集群代码
<?php
require 'vendor/autoload.php';
use Predis\Client;
// 集群配置
$parameters = [
'tcp://192.168.1.10:6379',
'tcp://192.168.1.11:6379',
'tcp://192.168.1.12:6379',
];
$options = [
'cluster' => 'redis',
'parameters' => [
'password' => 'your_password' // 如果设置了密码
]
];
$client = new Client($parameters, $options);
// ====== 基本操作 (和单机用法几乎一样) ======
$client->set('name', 'Predis Cluster');
echo $client->get('name');
// ====== 哈希操作 ======
$client->hset('user:1', 'email', '[email protected]');
$email = $client->hget('user:1', 'email');
// ====== 使用Lua脚本 ======
$script = 'return {KEYS[1], ARGV[1]}';
$result = $client->eval($script, 1, 'key1', 'arg1');
注意事项
- 性能:低于PhpRedis,因为它是纯PHP实现,高并发场景建议避坑。
- 自动故障转移:Predis本身不处理故障转移,需要结合 Sentinel 或外部健康检查。
- 连接池:Predis默认每个请求新建连接(无持久化),可通过配置
persistent选项开启持久连接。
核心配置与最佳实践
集群的种子节点
- 不需要列出全部节点,列出 3 到 5 个 种子节点即可,客户端连接后会通过
CLUSTER SLOTS命令自动获取完整的节点拓扑图。 - 节点变更(扩容、缩容):
RedisCluster对象在遇到MOVED错误时会自动更新本地缓存,但如果是长连接且长时间不刷新,可能会出错,建议定期(如每隔几分钟)重新创建连接对象,或者捕获MOVED异常后重试。 - 连接池:在循环或长时间运行的脚本中,不要每次都
new RedisCluster(),应该复用同一个对象,或者使用连接池。
密码认证
- 所有集群节点密码必须一致。
- PhpRedis:
$cluster->auth('password')(必须放在连接后第一句执行)。 - Predis:在
parameters中设置password。
键分布与 Hash Tag
- Redis 默认使用
CRC16(key) % 16384决定键存储在哪个节点。 - 如果需要多个键落在同一个节点上(例如关系数据),使用 Hash Tag:花括号 ,CRC16 只会计算 内的内容。
$cluster->set('{user:123}:name', 'Tom'); $cluster->set('{user:123}:age', '25'); // 这两个键在同一个节点
异常处理
try {
$result = $cluster->set('key', 'value');
} catch (RedisClusterException $e) {
// 连接失败、move重定向、节点宕机等情况
echo "集群操作失败: " . $e->getMessage();
// 可以在这里重新初始化连接或进行业务降级
}
性能优化建议
- 使用 Pipeline:减少网络往返,但注意 PhpRedis 的 Pipeline 只能针对单个节点,不能跨节点。
- 使用 MSET/MGET 时确保键落在同一节点(通过 Hash Tag),否则性能会大幅下降。
- 避免 KEYS 命令:在集群中特别危险,使用 SCAN 代替。
- 批量删除:没有直接的跨节点
DEL,需要依次删除或使用 Lua 脚本在单个节点执行del。
总结推荐
| 对比项 | PhpRedis (扩展) | Predis (纯PHP) |
|---|---|---|
| 安装难度 | 中等(需root权限安装扩展) | 简单(Composer引入) |
| 性能 | ||
| 集群功能完整度 | 高(自动分片、故障转移、MOVED重定向) | 中(需配合其他组件实现故障转移) |
| 生产环境推荐 | ✅ 首选 | ❌ 不推荐(性能差、故障处理弱) |
最终实现建议:
对于大多数生产项目,强烈推荐使用 PhpRedis 扩展,只需要在配置文件里维护节点列表(建议3-5个),然后直接使用 RedisCluster 类操作,Redis会自动处理槽位分配和连接,如果有密码,记得统一设置,如果是在资源受限的虚拟主机上,才考虑使用 Predis。