PHP 使用 Redis

PHP 使用 Redis 全攻略(2025 版)

目标:从 零到生产级,掌握 PHP 生态中最成熟、最稳定的 Redis 客户端 —— PhpRedis(C 扩展,性能最高)与 Predis(纯 PHP,易部署),覆盖 单机、集群、哨兵、连接池、Pipeline、事务、Lua、分布式锁、监控、运维 等全场景。


1. 客户端选型对比(2025 推荐)

客户端类型性能功能部署推荐场景
PhpRedisC 扩展5 星5 星(Cluster、Pipeline、Lua)需要编译生产首选
Predis纯 PHP3 星5 星(自动发现、灵活)Composer 安装开发、Serverless、无法装扩展
RedisentC 扩展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_PHPIGBINARY
$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 leakclose()使用连接池

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 TagCluster 多 key
分布式锁用 Lua 脚本防竞态
监控 连接数、延迟Prometheus
超时 < 500ms防止阻塞
Laravel 用 PhpRedisREDIS_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 + RoadRunnerRedis 缓存穿透/雪崩方案分布式限流Redis Stream 消息队列Docker 部署脚本?随时告诉我!

文章已创建 2481

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部