メインコンテンツまでスキップ

Redis

導入

Redis はオープンソースの高度なキー値ストアです。キーには文字列ハッシュリストセット、およびソート済みセットを含めることができるため、データ構造サーバーとしてしばしば言及されます。

LaravelでRedisを使用する前に、PECLを介してPhpRedis PHP拡張機能をインストールして使用することをお勧めします。この拡張機能は、"ユーザーランド"のPHPパッケージよりも複雑にインストールする必要がありますが、Redisを多用するアプリケーションにはより優れたパフォーマンスを提供する可能性があります。Laravel Sailを使用している場合、この拡張機能はすでにアプリケーションのDockerコンテナにインストールされています。

PhpRedis拡張機能をインストールできない場合は、Composerを介してpredis/predisパッケージをインストールすることができます。Predisは完全にPHPで書かれたRedisクライアントであり、追加の拡張機能は必要ありません:

composer require predis/predis:^2.0

設定

config/database.php構成ファイルを介してアプリケーションのRedis設定を構成することができます。このファイル内には、アプリケーションで使用されるRedisサーバーを含む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'),
],

],

構成ファイルで定義された各Redisサーバーには、名前、ホスト、およびポートが必要です。Redis接続を表す単一のURLを定義しない限り:

    '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' => 'tcp://127.0.0.1:6379?database=0',
],

'cache' => [
'url' => 'tls://user:password@127.0.0.1:6380?database=1',
],

],

接続スキームの構成

デフォルトでは、RedisクライアントはRedisサーバーに接続する際にtcpスキームを使用します。ただし、Redisサーバーの構成配列でscheme構成オプションを指定することで、TLS / SSL暗号化を使用することができます:

    '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サーバーのクラスタを利用している場合、これらのクラスタをRedis構成のclustersキー内に定義する必要があります。この構成キーはデフォルトでは存在しないため、アプリケーションのconfig/database.php構成ファイル内に作成する必要があります:

    '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'),
],
],
],

// ...
],

デフォルトでは、Laravelはoptions.cluster構成値がredisに設定されているため、ネイティブのRedisクラスタリングを使用します。Redisクラスタリングは優れたデフォルトオプションであり、障害の際に優雅に処理します。

Laravelはクライアント側のシャーディングもサポートしています。ただし、クライアント側のシャーディングは障害の処理を行わないため、主に他のプライマリデータストアから利用可能な一時的なキャッシュデータに適しています。

ネイティブのRedisクラスタリングの代わりにクライアント側のシャーディングを使用したい場合は、アプリケーションのconfig/database.php構成ファイル内でoptions.cluster構成値を削除することができます:

    'redis' => [

'client' => env('REDIS_CLIENT', 'phpredis'),

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

// ...
],

Predis

アプリケーションがPredisパッケージを介してRedisとやり取りするようにしたい場合は、REDIS_CLIENT環境変数の値がpredisになっていることを確認してください:

    'redis' => [

'client' => env('REDIS_CLIENT', 'predis'),

// ...
],

デフォルトの構成オプションに加えて、Predisは各Redisサーバーに対して定義できる追加の接続パラメータをサポートしています。これらの追加の構成オプションを利用するには、アプリケーションのconfig/database.php構成ファイル内のRedisサーバー構成に追加してください:

    '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,
],

PhpRedis

デフォルトでは、LaravelはPhpRedis拡張機能を使用してRedisと通信します。LaravelがRedisと通信するために使用するクライアントは、通常はREDIS_CLIENT環境変数の値を反映したredis.client構成オプションの値によって決まります:

    'redis' => [

'client' => env('REDIS_CLIENT', 'phpredis'),

// ...
],

デフォルトの構成オプションに加えて、PhpRedisは以下の追加の接続パラメータをサポートしています:namepersistentpersistent_idprefixread_timeoutretry_intervaltimeoutcontext。これらのオプションのいずれかをRedisサーバーの構成に追加することができます。config/database.php構成ファイル:```

    '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],
],
],

PhpRedis シリアル化と圧縮

PhpRedis 拡張機能は、さまざまなシリアライザと圧縮アルゴリズムを使用するように構成することもできます。これらのアルゴリズムは、Redis 構成の options 配列を介して構成できます:

    '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_PHPRedis::SERIALIZER_JSONRedis::SERIALIZER_IGBINARYRedis::SERIALIZER_MSGPACK が含まれます。

サポートされている圧縮アルゴリズムには、Redis::COMPRESSION_NONE(デフォルト)、Redis::COMPRESSION_LZFRedis::COMPRESSION_ZSTDRedis::COMPRESSION_LZ4 が含まれます。

Redis とのやり取り

Redis ファサード 上で様々なメソッドを呼び出すことで Redis とやり取りすることができます。Redis ファサードは動的メソッドをサポートしており、ファサード上で任意の Redis コマンド を呼び出すことができます。この例では、Redis ファサード上の get メソッドを呼び出すことで Redis の GET コマンドを呼び出します:

    <?php

namespace App\Http\Controllers;

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

class UserController extends Controller
{
/**
* Show the profile for the given user.
*/
public function show(string $id): View
{
return view('user.profile', [
'user' => Redis::get('user:profile:'.$id)
]);
}
}

前述のように、Redis ファサード上で Redis のコマンドを呼び出すことができます。Laravel はマジックメソッドを使用してコマンドを Redis サーバーに渡します。Redis コマンドが引数を必要とする場合は、それらをファサードの対応するメソッドに渡す必要があります:

    use Illuminate\Support\Facades\Redis;

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

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

また、Redis ファサードの command メソッドを使用して、コマンドの名前を第1引数として、値の配列を第2引数として受け入れる方法でサーバーにコマンドを渡すこともできます:

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

複数の Redis 接続を使用する

アプリケーションの config/database.php 構成ファイルを使用して、複数の Redis 接続 / サーバーを定義することができます。Redis ファサードの connection メソッドを使用して特定の Redis 接続に接続できます:

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

デフォルトの Redis 接続のインスタンスを取得するには、追加の引数なしで connection メソッドを呼び出すことができます:

    $redis = Redis::connection();

トランザクション

Redis ファサードの transaction メソッドは、Redis のネイティブな MULTI および EXEC コマンドを便利にラップします。transaction メソッドは、唯一の引数としてクロージャを受け入れます。このクロージャは Redis 接続インスタンスを受け取り、このインスタンスに対して任意のコマンドを発行することができます。クロージャ内で発行されたすべての Redis コマンドは、単一のアトミックトランザクションで実行されます:

    use Redis;
use Illuminate\Support\Facades;

Facades\Redis::transaction(function (Redis $redis) {
$redis->incr('user_visits', 1);
$redis->incr('total_visits', 1);
});

警告

Redis トランザクションを定義する際には、Redis 接続から値を取得してはいけません。トランザクションは単一のアトミック操作として実行され、その操作はクロージャ全体がコマンドの実行を終えるまで実行されません。

Lua スクリプト

eval メソッドは、単一のアトミック操作で複数の Redis コマンドを実行する別の方法を提供します。ただし、eval メソッドはその操作中に Redis キーの値とやり取りすることができる利点があります。Redis スクリプトは Lua プログラミング言語 で記述されます。

eval メソッドは最初は少し怖いかもしれませんが、最初の例を見てみて、その使い方を理解していきましょう。eval メソッドにはいくつかの引数が必要です。まず、Lua スクリプト(文字列として)をメソッドに渡す必要があります。次に、スクリプトが対話するキーの数(整数として)を渡す必要があります。三番目に、それらのキーの名前を渡す必要があります。最後に、スクリプト内でアクセスする必要がある他の追加の引数を渡すことができます。

この例では、カウンターをインクリメントし、その新しい値を検査し、最初のカウンターの値が 5 を超える場合に第二のカウンターをインクリメントします。最後に、最初のカウンターの値を返します:

    $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');

警告

Redis スクリプティングに関する詳細情報については、Redis ドキュメント を参照してください。

コマンドのパイプライン処理

時には、数十の Redis コマンドを実行する必要があるかもしれません。各コマンドごとに Redis サーバーにネットワークトリップを行う代わりに、pipeline メソッドを使用することができます。pipeline メソッドは、Redis インスタンスを受け取るクロージャを引数として受け入れます。この Redis インスタンスに対してすべてのコマンドを発行し、それらはすべて同時に Redis サーバーに送信され、サーバーへのネットワークトリップを減らすために実行されます。コマンドは発行された順序で実行されます:

    use Redis;
use Illuminate\Support\Facades;

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

パブ / サブ

LaravelはRedisのpublishおよびsubscribeコマンドに対する便利なインターフェースを提供しています。これらのRedisコマンドを使用すると、指定された「チャンネル」でメッセージをリッスンすることができます。別のアプリケーションから、または別のプログラミング言語を使用して、チャンネルにメッセージを公開することができ、アプリケーションやプロセス間の簡単な通信が可能になります。

まず、subscribeメソッドを使用してチャンネルリスナーをセットアップしましょう。このメソッド呼び出しは、subscribeメソッドを呼び出すと長時間実行されるプロセスが開始されるため、Artisanコマンド内にこのメソッド呼び出しを配置します:

    <?php

namespace App\Console\Commands;

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

class RedisSubscribe extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'redis:subscribe';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Subscribe to a Redis channel';

/**
* Execute the console command.
*/
public function handle(): void
{
Redis::subscribe(['test-channel'], function (string $message) {
echo $message;
});
}
}

これで、publishメソッドを使用してチャンネルにメッセージを公開できます:

    use Illuminate\Support\Facades\Redis;

Route::get('/publish', function () {
// ...

Redis::publish('test-channel', json_encode([
'name' => 'Adam Wathan'
]));
});

ワイルドカードサブスクリプション

psubscribeメソッドを使用すると、ワイルドカードチャンネルにサブスクライブすることができます。これは、すべてのチャンネルでのすべてのメッセージをキャッチするのに役立ちます。チャンネル名は、提供されたクロージャの第2引数として渡されます:

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

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