Redis

简介

Redis 是一个开源的、先进的键值对存储数据库。由于支持的数据类型包含 字符串哈希列表集合有序集合,因此经常被称为数据结构服务器。

在 Laravel 中使用 Redis 之前,将需要通过 Composer 安装 predis/predis 扩展包:

composer require predis/predis

或者可以通过 PECL 安装 PhpRedis PHP 扩展。此扩展安装更复杂但是对大量使用 Redis 的应用可能有更好的性能。

配置

应用的 Redis 配置位于 config/database.php 配置文件。在此文件中,可以看到一个包含应用使用的所有 Redis 服务器的 redis 数组:

'redis' => [

    'client' => 'predis',

    'default' => [
        'host' => env('REDIS_HOST', 'localhost'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => 0,
    ],

],

默认的服务器配置应该能满足开发。不过,可以根据环境自由修改此数组。配置文件中定义的每个 Redis 服务器都要求有一个名称,主机和端口。

配置集群

如果应用使用 Redis 服务器集群,应该在 Redis 配置的 clusters 键中定义这些集群:

'redis' => [

    'client' => 'predis',

    'clusters' => [
        'default' => [
            [
                'host' => env('REDIS_HOST', 'localhost'),
                'password' => env('REDIS_PASSWORD', null),
                'port' => env('REDIS_PORT', 6379),
                'database' => 0,
            ],
        ],
    ],

],

默认情况下,集群会跨节点实现客户端共享,允许您将节点组成节点池创建大量可用内存。但是,需要注意的是,客户端共享不会进行容错处理;因此,主要适用于缓存另一个主数据库中可用的数据。如果要使用原生的 Redis 集群,应该在 Redis 配置的 options 键中指定:

'redis' => [

    'client' => 'predis',

    'options' => [
        'cluster' => 'redis',
    ],

    'clusters' => [
        // ...
    ],

],

Predis

除了默认的 hostportdatabasepassword 服务器配置选项外,Predis 还支持定义每个 Redis 服务器的额外 连接参数。要使用这些额外选项,可以将其添加到 config/database.php 配置文件中的 Redis 服务器配置:

'default' => [
    'host' => env('REDIS_HOST', 'localhost'),
    'password' => env('REDIS_PASSWORD', null),
    'port' => env('REDIS_PORT', 6379),
    'database' => 0,
    'read_write_timeout' => 60,
],

PhpRedis

使用 PhpRedis 扩展,应该将 Redis 配置的 client 选项更改为 phpredis。此选项可以在 config/database.php 配置文件中找到:

'redis' => [

    'client' => 'phpredis',

    // Rest of Redis configuration...
],

除了默认的 hostportdatabasepassword 服务器配置选项外,PhpRedis 还支持如下额外的连接参数:persistentprefixread_timeouttimeout。可以将其添加到 config/database.php 配置文件中的 Redis 服务器配置:

'default' => [
    'host' => env('REDIS_HOST', 'localhost'),
    'password' => env('REDIS_PASSWORD', null),
    'port' => env('REDIS_PORT', 6379),
    'database' => 0,
    'read_timeout' => 60,
],

Redis 交互

可以调用 Redis Facade 的各种方法与 Redis 交互。Redis Facade 支持动态方法,意味着可以调用 Facade 的任何 Redis 命令, 这些命令会被直接传递给 Redis。在此示例中,我们将通过调用 Redis Facade 的 get 方法调用 Redis 的 GET 命令:

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Redis;

class UserController extends Controller
{
    /**
     * 显示给定用户的配置信息
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        $user = Redis::get('user:profile:'.$id);

        return view('user.profile', ['user' => $user]);
    }
}

当然,如之前所述,可以在 Redis Facade 上调用任何 Redis 命令。Laravel 使用魔术方法将命令传递给 Redis 服务器,因此要传递 Redis 命令所需的参数:

Redis::set('name', 'Taylor');

$values = Redis::lrange('names', 5, 10);

或者,也可以使用 command 命令将命令传递给服务器,此命令接收命令名称作为其第一个参数,和一个数组值作为其第二个参数:

$values = Redis::command('lrange', ['name', 5, 10]);

使用多个 Redis 连接

可以通过调用 Redis::connection 方法得到一个 Redis 实例:

$redis = Redis::connection();

以上会得到一个 Redis 默认服务器的实例。也可以传递连接或集群名称给 connection,得到一个定义在 Redis 配置中的指定的服务器或集群:

$redis = Redis::connection('my-connection');

管道命令

当需要在一个操作中向服务器发送很多命令时,应该使用管道命令。pipeline 接收一个参数:一个接收 Redis 实例的闭包。可以将全部命令发送给此 Redis 实例,所有命令会在单个操作中执行:

Redis::pipeline(function ($pipe) {
    for ($i = 0; $i < 1000; $i++) {
        $pipe->set("key:$i", $i);
    }
});

发布/订阅

Laravel 为 Redis 的 publishsubscribe 命令提供了一个方便的接口。这些 Redis 命令允许您监听给定「频道」上的信息。可以从另一个应用发布信息到频道,或者甚至使用另一种编程语言,这让应用和进程间的通信更加容易。

首先,我们使用 subscribe 方法设置一个频道监听器。我们将在 Artisan 命令 中调用此方法,因为调用 subscribe 方法会启动一个长时间运行的进程:

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;

class RedisSubscribe extends Command
{
    /**
     * 终端命令的名称和参数
     *
     * @var string
     */
    protected $signature = 'redis:subscribe';

    /**
     * 终端命令描述
     *
     * @var string
     */
    protected $description = 'Subscribe to a Redis channel';

    /**
     * 执行终端命令
     *
     * @return mixed
     */
    public function handle()
    {
        Redis::subscribe(['test-channel'], function ($message) {
            echo $message;
        });
    }
}

现在我们可以使用 publish 方法将信息发送到频道:

Route::get('publish', function () {
    // 路由逻辑

    Redis::publish('test-channel', json_encode(['foo' => 'bar']));
});

通配符订阅

使用 psubscribe 方法,可以订阅通配符频道,用于获取所有频道上的所有信息。$channel 名称可以作为第二个参数传递给提供的回调闭包:

Redis::psubscribe(['*'], function ($message, $channel) {
    echo $message;
});

Redis::psubscribe(['users.*'], function ($message, $channel) {
    echo $message;
});