PHP 使用 Redis 全攻略(2025 版)
目标:从 零到生产级,掌握 PHP 生态中最成熟、最稳定的 Redis 客户端 —— PhpRedis(C 扩展,性能最高)与 Predis(纯 PHP,易部署),覆盖 单机、集群、哨兵、连接池、Pipeline、事务、Lua、分布式锁、监控、运维 等全场景。
1. 客户端选型对比(2025 推荐)
| 客户端 | 类型 | 性能 | 功能 | 部署 | 推荐场景 |
|---|---|---|---|---|---|
| PhpRedis | C 扩展 | 5 星 | 5 星(Cluster、Pipeline、Lua) | 需要编译 | 生产首选 |
| Predis | 纯 PHP | 3 星 | 5 星(自动发现、灵活) | Composer 安装 | 开发、Serverless、无法装扩展 |
| Redisent | C 扩展 | 4 星 | 4 星 | 需编译 | 轻量替代 |
结论:生产用 PhpRedis,开发/无扩展环境用 Predis
2. 环境准备
2.1 安装 PhpRedis(推荐)
# Ubuntu/Debian
sudo apt install php-redis
# CentOS/RHEL
sudo yum install php-pecl-redis
# 或源码编译(PHP 8.3+)
pecl install redis
echo "extension=redis.so" > /etc/php/8.3/mods-available/redis.ini
phpenmod redis
验证:
<?php
if (extension_loaded('redis')) {
echo "PhpRedis 已启用\n";
phpinfo();
}
2.2 安装 Predis(Composer)
composer require predis/predis
3. 基础连接(PhpRedis)
<?php
$redis = new Redis();
// 单机连接
$redis->connect('127.0.0.1', 6379, 0.5); // 超时 500ms
$redis->auth('YourStrongP@ssw0rd');
$redis->set('name', 'PHP Redis');
echo $redis->get('name'); // PHP Redis
$redis->close();
TLS 连接
$redis->connect('tls://redis-prod.example.com', 6379, 0.5, null, 0, 0, [
'ssl' => [
'verify_peer' => true,
'cafile' => '/path/to/ca.crt',
'verify_peer_name' => true
]
]);
4. Laravel 集成(PhpRedis 默认)
4.1 .env
REDIS_HOST=redis-prod.example.com
REDIS_PASSWORD=YourStrongP@ssw0rd
REDIS_PORT=6379
REDIS_DB=0
REDIS_CLIENT=phpredis
REDIS_SSL=true
4.2 config/database.php
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', 'laravel_'),
'ssl' => ['verify_peer' => true],
],
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => env('REDIS_DB', 0),
'timeout' => 0.5,
],
],
4.3 使用
use Illuminate\Support\Facades\Redis;
Redis::set('framework', 'Laravel + PhpRedis');
echo Redis::get('framework');
5. 高可用连接
5.1 Sentinel(哨兵)
$sentinels = ['tcp://sentinel1:26379', 'tcp://sentinel2:26379'];
$redis = new Redis();
foreach ($sentinels as $sentinel) {
try {
$redis->connect($sentinel, 0.1);
$master = $redis->rawCommand('SENTINEL', 'get-master-addr-by-name', 'mymaster');
if ($master) {
$redis->connect("tcp://{$master[0]}", $master[1]);
break;
}
} catch (Exception $e) {
continue;
}
}
Laravel 配置:
REDIS_CLIENT=phpredis
REDIS_SENTINEL_MASTER=mymaster
REDIS_SENTINELS=sentinel1:26379,sentinel2:26379
5.2 Redis Cluster
$redis = new Redis();
$redis->connect('127.0.0.1', 7000); // 任意节点
// 自动重定向
$redis->set('{user:1000}:name', '张三');
echo $redis->get('{user:1000}:name');
Laravel 配置:
REDIS_CLUSTER=redis
REDIS_HOSTS=127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002
6. 高级特性
6.1 Pipeline 批量操作
$redis->pipeline();
for ($i = 0; $i < 1000; $i++) {
$redis->set("key:$i", "value:$i");
}
$results = $redis->exec(); // 一次性返回 1000 个 OK
6.2 事务(MULTI/EXEC)
$redis->multi();
$redis->incr('counter');
$redis->incr('counter');
$results = $redis->exec(); // [1, 2]
6.3 Lua 脚本
$script = "
local key = KEYS[1]
local inc = tonumber(ARGV[1])
local val = redis.call('GET', key) or '0'
local new = tonumber(val) + inc
redis.call('SET', key, new)
return new
";
$result = $redis->eval($script, ['counter', 5], 1);
7. 连接池(Swoole / RoadRunner)
Swoole 协程连接池
use Swoole\Redis\Pool;
$pool = new Pool(function () {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('password');
return $redis;
}, 50); // 最大 50 连接
$redis = $pool->get();
$redis->set('key', 'value');
$pool->put($redis);
8. 分布式锁(RedLock 算法)
function acquireLock($redis, $lockKey, $ttl = 10) {
$identifier = uniqid();
$end = time() + $ttl;
while (time() < $end) {
if ($redis->set($lockKey, $identifier, ['NX', 'EX' => $ttl])) {
return $identifier;
}
usleep(100000); // 100ms
}
return false;
}
function releaseLock($redis, $lockKey, $identifier) {
$script = "
if redis.call('GET', KEYS[1]) == ARGV[1] then
return redis.call('DEL', KEYS[1])
else
return 0
end
";
return $redis->eval($script, [$lockKey, $identifier], 1);
}
9. 性能优化
| 优化点 | 配置 |
|---|---|
| Pipeline | 批量 > 50 条 |
| 连接池 | Swoole/RoadRunner |
| 持久连接 | pconnect |
| 压缩 | setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_LZF) |
| 序列化 | Redis::SERIALIZER_PHP 或 IGBINARY |
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_IGBINARY);
$redis->setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_LZ4);
10. 监控与运维
10.1 Laravel Telescope / Horizon
// Horizon 队列监控 Redis 连接
10.2 Prometheus 导出
use Prometheus\CollectorRegistry;
use Prometheus\RenderTextFormat;
$registry = new CollectorRegistry(new \Prometheus\Storage\APCU());
$counter = $registry->getOrRegisterCounter('php', 'redis_commands_total', 'Redis 命令总数');
$counter->inc(['command' => 'SET']);
10.3 连接健康检查
public function checkRedis()
{
try {
$pong = Redis::connection()->client()->ping();
return $pong === '+PONG';
} catch (Exception $e) {
return false;
}
}
11. 生产级配置模板(Laravel)
# .env.production
REDIS_CLIENT=phpredis
REDIS_HOST=redis-prod.example.com
REDIS_PASSWORD=${REDIS_PASSWORD}
REDIS_PORT=6379
REDIS_DB=0
REDIS_SSL=true
REDIS_TIMEOUT=0.5
REDIS_READ_TIMEOUT=0.5
# Cluster
REDIS_CLUSTER=redis
REDIS_HOSTS=node1:6379,node2:6379,node3:6379
12. 常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
Connection refused | 防火墙 | 检查安全组 |
MOVED | 非 Cluster 模式 | 使用 Cluster 客户端 |
NOAUTH | 密码错误 | 检查 auth() |
RedisException: read error on connection | 超时 | 设置 timeout |
Memory leak | 未 close() | 使用连接池 |
13. 一键健康检查脚本
<?php
// redis_health.php
require 'vendor/autoload.php';
$redis = new Redis();
try {
$redis->connect('127.0.0.1', 6379, 0.5);
$redis->auth('password');
$pong = $redis->ping();
echo "Redis 健康: $pong\n";
$info = $redis->info();
echo "连接数: " . $info['connected_clients'] . "\n";
echo "内存: " . $info['used_memory_human'] . "\n";
} catch (Exception $e) {
echo "Redis 连接失败: " . $e->getMessage() . "\n";
exit(1);
}
14. 最佳实践清单(Checklist)
| 项目 | 检查 |
|---|---|
| 使用 PhpRedis | 性能最高 |
| 开启 持久连接 | pconnect |
| 批量操作 Pipeline | > 50 条 |
| 启用 IGBINARY + LZ4 | 节省带宽 |
| 使用 Hash Tag | Cluster 多 key |
| 分布式锁用 Lua 脚本 | 防竞态 |
| 监控 连接数、延迟 | Prometheus |
| 超时 < 500ms | 防止阻塞 |
| Laravel 用 PhpRedis | REDIS_CLIENT=phpredis |
小结:PHP + Redis 技术栈图谱
graph TD
A[PHP 应用] --> B[Laravel / Symfony / Swoole]
B --> C[PhpRedis 客户端]
C --> D[单机 / Sentinel / Cluster]
B --> E[Predis]
E --> F[Serverless / 开发环境]
C --> G[Pipeline / Lua / 事务]
B --> H[Prometheus + Grafana]
彩蛋:Redis 8+ JSON 支持(PhpRedis 6+)
$redis->jsonSet('doc:1', '$', json_encode(['name' => '张三']));
$name = $redis->jsonGet('doc:1', '$.name');
需要 Swoole 协程连接池、Laravel Octane + RoadRunner、Redis 缓存穿透/雪崩方案、分布式限流、Redis Stream 消息队列 或 Docker 部署脚本?随时告诉我!