本文目录导读:

在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。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播