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
設定
アプリケーションのRedis設定は、config/database.php
設定ファイルで設定できます。このファイル内には、アプリケーションで使用される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' => [ ], ],
接続スキームの設定
デフォルトでは、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'), ], ], ], // ...],
デフォルトでは、options.cluster
設定値がredis
に設定されているため、Laravelはネイティブ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は、name
、persistent
、persistent_id
、prefix
、read_timeout
、retry_interval
、timeout
、context
の追加の接続パラメータをサポートしています。これらのオプションのいずれかを、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_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_PHP
、Redis::SERIALIZER_JSON
、Redis::SERIALIZER_IGBINARY
、Redis::SERIALIZER_MSGPACK
が含まれます。
サポートされている圧縮アルゴリズムには、Redis::COMPRESSION_NONE
(デフォルト)、Redis::COMPRESSION_LZF
、Redis::COMPRESSION_ZSTD
、Redis::COMPRESSION_LZ4
が含まれます。
Redisとのインタラクション
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
メソッドを使用して、コマンドをサーバーに渡すこともできます。このメソッドは、最初の引数としてコマンドの名前、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スクリプト(文字列として)をメソッドに渡す必要があります。次に、スクリプトが対話するキーの数(整数として)を渡す必要があります。3番目に、それらのキーの名前を渡す必要があります。最後に、スクリプト内でアクセスする必要があるその他の追加引数を渡すことができます。
この例では、カウンターをインクリメントし、その新しい値を検査し、最初のカウンターの値が5より大きい場合は、2番目のカウンターをインクリメントします。最後に、最初のカウンターの値を返します。
$value = Redis::eval(<<<'LUA' local counter = redis.call("incr", KEYS[1]) if counter > 5 then redis.call("incr", KEYS[2]) end return counterLUA, 2, 'first-counter', 'second-counter');
Redisスクリプトの詳細については、Redisドキュメントを参照してください。
コマンドのパイプライン処理
時には、数十個のRedisコマンドを実行する必要があるかもしれません。各コマンドごとにRedisサーバーへのネットワーク通信を行う代わりに、pipeline
メソッドを使用することができます。pipeline
メソッドは、Redisインスタンスを受け取るクロージャを引数として1つ受け取ります。この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); }});
Pub / Sub
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;});