Redis 是一款内存型的键值存储,是 Laravel 众多功能的后端选择。
本文介绍从配置到操作,再到 Pub/Sub 的完整用法。
什么是 Redis
Redis 是一款开源的高性能键值存储。
它支持字符串、哈希、列表、集合、有序集合等多种数据结构,因此也被称作数据结构服务器。
Laravel 中 Redis 通常用于以下用途。
选择客户端
Laravel 支持两种客户端:PhpRedis(PHP 扩展)和 Predis(PHP 库)。
| 项目 | PhpRedis | Predis |
|---|
| 实现 | 用 C 编写的 PHP 扩展 | 纯 PHP 库 |
| 安装 | 需要 PECL 扩展 | 通过 composer require 完成 |
| 性能 | 更快 | 略慢于 PhpRedis |
| Laravel Sail | 默认预装 | 需另行安装 |
| 推荐场景 | 生产环境 | 开发环境或安装扩展受限时 |
Laravel 13 的默认客户端是 PhpRedis。生产环境推荐使用 PhpRedis。
使用 Laravel Sail 时 PhpRedis 已经预装。
config/database.php
Redis 的配置放在 config/database.php 的 redis 数组中。
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
],
],
环境变量
在 .env 中配置连接信息。
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=null
REDIS_DB=0
REDIS_CACHE_DB=1
也支持使用 URL 形式配置。
'default' => [
'url' => 'tcp://127.0.0.1:6379?database=0',
],
'cache' => [
'url' => 'tls://user:[email protected]:6380?database=1',
],
TLS / SSL 连接
若要使用 TLS 加密,请指定 scheme 选项。
'default' => [
'scheme' => 'tls',
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
以集群方式使用多台 Redis 时使用 clusters 键。
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
'clusters' => [
'default' => [
[
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
],
],
],
默认情况下 options.cluster 为 redis,使用原生的 Redis 集群模式,
它会自动处理故障切换,适合生产环境。
如果使用 Predis 的客户端侧分片,请删除 options.cluster。
但客户端侧分片不处理故障切换,只适合缓存等一次性数据。
Predis 的配置
使用 Predis 需要安装 predis/predis 并把 REDIS_CLIENT 改为 predis。
composer require predis/predis
可以指定 Predis 特有的连接参数。
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
'read_write_timeout' => 60,
],
Predis 的重试设置
Predis 3.4.0 及以上版本内置了重试与退避设置。使用 max_retries 设置重试次数,retry 设置退避策略。retry 选项接收一个数组,其中键是 NoBackoff、EqualBackoff 或 ExponentialBackoff 的类名。
use Predis\Retry\Strategy\ExponentialBackoff;
'default' => [
'url' => env('REDIS_URL'),
// ...
'retry' => [
ExponentialBackoff::class => [
env('REDIS_BACKOFF_BASE', 100),
env('REDIS_BACKOFF_CAP', 1000),
true, // 开启抖动
],
],
'max_retries' => env('REDIS_MAX_RETRIES', 3),
],
在 Redis 集群下使用 Predis 时,通过集群设置里的 parameters 选项配置重试。
use Predis\Retry\Strategy\NoBackoff;
'clusters' => [
'default' => [
// ...
],
],
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'parameters' => [
'retry' => [
NoBackoff::class => [],
],
'max_retries' => env('REDIS_MAX_RETRIES', 3),
],
],
PhpRedis 的配置
PhpRedis 通过 PECL 安装(Laravel Sail 已预装)。
它还支持以下额外选项:
name、persistent、persistent_id、prefix、read_timeout、retry_interval、
max_retries、backoff_algorithm、backoff_base、backoff_cap、timeout、context。
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
'read_timeout' => 60,
'context' => [
// 'auth' => ['username', 'secret'],
// 'stream' => ['verify_peer' => false],
],
],
重试与退避设置
用来配置连接失败时的重试行为。
支持的退避算法有:default、decorrelated_jitter、equal_jitter、exponential、uniform、constant。
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
'max_retries' => env('REDIS_MAX_RETRIES', 3),
'backoff_algorithm' => env('REDIS_BACKOFF_ALGORITHM', 'decorrelated_jitter'),
'backoff_base' => env('REDIS_BACKOFF_BASE', 100),
'backoff_cap' => env('REDIS_BACKOFF_CAP', 1000),
],
使用 Unix 套接字
当 Redis 与应用在同一台机器上时,通过 Unix 套接字连接可以减少 TCP 开销。
REDIS_HOST=/run/redis/redis.sock
REDIS_PORT=0
序列化与压缩
PhpRedis 允许配置存储数据的序列化和压缩算法。
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
'serializer' => Redis::SERIALIZER_MSGPACK,
'compression' => Redis::COMPRESSION_LZ4,
],
],
支持的序列化器:
| 常量 | 说明 |
|---|
Redis::SERIALIZER_NONE | 不序列化(默认) |
Redis::SERIALIZER_PHP | PHP 原生序列化 |
Redis::SERIALIZER_JSON | JSON |
Redis::SERIALIZER_IGBINARY | igbinary |
Redis::SERIALIZER_MSGPACK | MessagePack |
支持的压缩算法:
| 常量 | 说明 |
|---|
Redis::COMPRESSION_NONE | 不压缩(默认) |
Redis::COMPRESSION_LZF | LZF |
Redis::COMPRESSION_ZSTD | Zstandard |
Redis::COMPRESSION_LZ4 | LZ4 |
与 Redis 交互
Redis Facade
通过 Redis Facade 可以执行任何 Redis 命令。
Facade 通过魔术方法把命令转发给 Redis 服务器。
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Redis;
use Illuminate\View\View;
class UserController extends Controller
{
public function show(string $id): View
{
return view('user.profile', [
'user' => Redis::get('user:profile:'.$id)
]);
}
}
带参数的命令直接以方法参数传入。
use Illuminate\Support\Facades\Redis;
Redis::set('name', 'Taylor');
$values = Redis::lrange('names', 5, 10);
也可以通过 command 方法显式指定命令名和参数。
$values = Redis::command('lrange', ['name', 5, 10]);
多连接切换
可以在 config/database.php 中定义多个 Redis 连接,通过 connection() 方法切换。
// 取指定名字的连接
$redis = Redis::connection('connection-name');
// 取默认连接
$redis = Redis::connection();
transaction() 方法封装了 Redis 的 MULTI/EXEC。
闭包中的所有命令会原子地执行。
use Redis;
use Illuminate\Support\Facades;
Facades\Redis::transaction(function (Redis $redis) {
$redis->incr('user_visits', 1);
$redis->incr('total_visits', 1);
});
事务中无法从 Redis 读取值。
因为整个闭包会在收到 EXEC 后一次性执行。
Lua 脚本
eval() 方法可以原子性地执行 Lua 脚本。
比事务更灵活,脚本内可以引用与更新 Redis 中的值。
$value = Redis::eval(<<<'LUA'
local counter = redis.call("incr", KEYS[1])
if counter > 5 then
redis.call("incr", KEYS[2])
end
return counter
LUA, 2, 'first-counter', 'second-counter');
参数顺序:Lua 脚本 → 键数量 → 键名… → 附加参数…
KEYS[1]、KEYS[2] 是键名,ARGV[1] 起是附加参数。
管道(Pipeline)
一次性发送大量命令,可减少网络往返。
use Redis;
use Illuminate\Support\Facades;
Facades\Redis::pipeline(function (Redis $pipe) {
for ($i = 0; $i < 1000; $i++) {
$pipe->set("key:$i", $i);
}
});
管道只是打包发送命令,不保证原子性。
如果需要原子性,请使用事务或 Lua 脚本。
Pub / Sub
Redis 的 publish / subscribe 命令可用于通过频道传递消息。
订阅者
subscribe() 是一个长时间运行的过程,通常在 Artisan 命令中调用。
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
class RedisSubscribe extends Command
{
protected $signature = 'redis:subscribe';
protected $description = 'Subscribe to a Redis channel';
public function handle(): void
{
Redis::subscribe(['test-channel'], function (string $message) {
echo $message;
});
}
}
发布者
从其他请求或进程中发送消息。
use Illuminate\Support\Facades\Redis;
Route::get('/publish', function () {
Redis::publish('test-channel', json_encode([
'name' => 'Adam Wathan'
]));
});
通配符订阅
使用 psubscribe() 可以按模式匹配进行订阅。
// 订阅所有频道
Redis::psubscribe(['*'], function (string $message, string $channel) {
echo $message;
});
// 订阅 users.* 模式的频道
Redis::psubscribe(['users.*'], function (string $message, string $channel) {
echo $message;
});
- 生产环境:PhpRedis(PECL 扩展,性能好)
- 开发环境或不方便安装扩展:Predis(Composer 包)
- Laravel Sail:默认已包含 PhpRedis
- 多个 Redis 连接在
config/database.php 中按用途分开(default / cache 等)
- 集群环境使用
clusters 键
- 生产环境建议开启 TLS 并配置认证信息
| 操作 | 用途 |
|---|
| Facade 方法 | 常规 Redis 命令 |
transaction() | 多命令原子执行(不能读取值) |
eval() | Lua 脚本(支持读取的原子操作) |
pipeline() | 大量命令的快速发送(非原子) |
subscribe() / publish() | 频道消息传递(Pub/Sub) |