はじめに

Redisはオープンソースの高度なキー・バリューストアです。キーにはstringhasheslistssets、およびsorted setsを含むことができるため、データ構造サーバーとも呼ばれます。

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

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

  1. composer require predis/predis:^2.0

設定

アプリケーションのRedis設定は、config/database.php設定ファイルを介して構成できます。このファイル内には、アプリケーションで使用されるRedisサーバーを含むredis配列が表示されます:

  1. 'redis' => [
  2. 'client' => env('REDIS_CLIENT', 'phpredis'),
  3. 'options' => [
  4. 'cluster' => env('REDIS_CLUSTER', 'redis'),
  5. 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
  6. ],
  7. 'default' => [
  8. 'url' => env('REDIS_URL'),
  9. 'host' => env('REDIS_HOST', '127.0.0.1'),
  10. 'username' => env('REDIS_USERNAME'),
  11. 'password' => env('REDIS_PASSWORD'),
  12. 'port' => env('REDIS_PORT', '6379'),
  13. 'database' => env('REDIS_DB', '0'),
  14. ],
  15. 'cache' => [
  16. 'url' => env('REDIS_URL'),
  17. 'host' => env('REDIS_HOST', '127.0.0.1'),
  18. 'username' => env('REDIS_USERNAME'),
  19. 'password' => env('REDIS_PASSWORD'),
  20. 'port' => env('REDIS_PORT', '6379'),
  21. 'database' => env('REDIS_CACHE_DB', '1'),
  22. ],
  23. ],

設定ファイルに定義された各Redisサーバーには、名前、ホスト、およびポートが必要です。単一のURLを定義してRedis接続を表す場合を除きます:

  1. 'redis' => [
  2. 'client' => env('REDIS_CLIENT', 'phpredis'),
  3. 'options' => [
  4. 'cluster' => env('REDIS_CLUSTER', 'redis'),
  5. 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
  6. ],
  7. 'default' => [
  8. 'url' => 'tcp://127.0.0.1:6379?database=0',
  9. ],
  10. 'cache' => [
  11. 'url' => 'tls://user::6380?database=1',
  12. ],
  13. ],

接続スキームの設定

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

  1. 'default' => [
  2. 'scheme' => 'tls',
  3. 'url' => env('REDIS_URL'),
  4. 'host' => env('REDIS_HOST', '127.0.0.1'),
  5. 'username' => env('REDIS_USERNAME'),
  6. 'password' => env('REDIS_PASSWORD'),
  7. 'port' => env('REDIS_PORT', '6379'),
  8. 'database' => env('REDIS_DB', '0'),
  9. ],

クラスター

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

  1. 'redis' => [
  2. 'client' => env('REDIS_CLIENT', 'phpredis'),
  3. 'options' => [
  4. 'cluster' => env('REDIS_CLUSTER', 'redis'),
  5. 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
  6. ],
  7. 'clusters' => [
  8. 'default' => [
  9. [
  10. 'url' => env('REDIS_URL'),
  11. 'host' => env('REDIS_HOST', '127.0.0.1'),
  12. 'username' => env('REDIS_USERNAME'),
  13. 'password' => env('REDIS_PASSWORD'),
  14. 'port' => env('REDIS_PORT', '6379'),
  15. 'database' => env('REDIS_DB', '0'),
  16. ],
  17. ],
  18. ],
  19. // ...
  20. ],

デフォルトでは、Laravelはoptions.cluster設定値がredisに設定されているため、ネイティブRedisクラスターを使用します。Redisクラスターは、フェイルオーバーを優雅に処理するため、優れたデフォルトオプションです。

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

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

  1. 'redis' => [
  2. 'client' => env('REDIS_CLIENT', 'phpredis'),
  3. 'clusters' => [
  4. // ...
  5. ],
  6. // ...
  7. ],

Predis

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

  1. 'redis' => [
  2. 'client' => env('REDIS_CLIENT', 'predis'),
  3. // ...
  4. ],

デフォルトの設定オプションに加えて、Predisは各Redisサーバーに対して定義できる追加の[接続パラメータ](https://github.com/nrk/predis/wiki/Connection-Parametersをサポートしています。これらの追加の設定オプションを利用するには、アプリケーションの`````config/database.php`````設定ファイル内のRedisサーバー設定に追加してください:

  1. 'default' => [
  2. 'url' => env('REDIS_URL'),
  3. 'host' => env('REDIS_HOST', '127.0.0.1'),
  4. 'username' => env('REDIS_USERNAME'),
  5. 'password' => env('REDIS_PASSWORD'),
  6. 'port' => env('REDIS_PORT', '6379'),
  7. 'database' => env('REDIS_DB', '0'),
  8. 'read_write_timeout' => 60,
  9. ],

PhpRedis

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

  1. 'redis' => [
  2. 'client' => env('REDIS_CLIENT', 'phpredis'),
  3. // ...
  4. ],

デフォルトの設定オプションに加えて、PhpRedisは次の追加の接続パラメータをサポートしています: namepersistentpersistent_idprefixread_timeoutretry_intervaltimeout、およびcontext。これらのオプションのいずれかをconfig/database.php設定ファイル内のRedisサーバー設定に追加できます:

  1. 'default' => [
  2. 'url' => env('REDIS_URL'),
  3. 'host' => env('REDIS_HOST', '127.0.0.1'),
  4. 'username' => env('REDIS_USERNAME'),
  5. 'password' => env('REDIS_PASSWORD'),
  6. 'port' => env('REDIS_PORT', '6379'),
  7. 'database' => env('REDIS_DB', '0'),
  8. 'read_timeout' => 60,
  9. 'context' => [
  10. // 'auth' => ['username', 'secret'],
  11. // 'stream' => ['verify_peer' => false],
  12. ],
  13. ],

PhpRedisのシリアル化と圧縮

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

  1. 'redis' => [
  2. 'client' => env('REDIS_CLIENT', 'phpredis'),
  3. 'options' => [
  4. 'cluster' => env('REDIS_CLUSTER', 'redis'),
  5. 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
  6. 'serializer' => Redis::SERIALIZER_MSGPACK,
  7. 'compression' => Redis::COMPRESSION_LZ4,
  8. ],
  9. // ...
  10. ],

現在サポートされているシリアライザーには、Redis::SERIALIZER_NONE(デフォルト)、Redis::SERIALIZER_PHPRedis::SERIALIZER_JSONRedis::SERIALIZER_IGBINARY、およびRedis::SERIALIZER_MSGPACKが含まれます。

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

Redisとの対話

さまざまなメソッドを呼び出すことでRedisと対話できます。Redis ファサードRedisファサードは動的メソッドをサポートしており、ファサードで任意のRedisコマンドを呼び出すことができ、そのコマンドは直接Redisに渡されます。この例では、Redisファサードのgetメソッドを呼び出してRedisのGETコマンドを呼び出します:

  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\Http\Controllers\Controller;
  4. use Illuminate\Support\Facades\Redis;
  5. use Illuminate\View\View;
  6. class UserController extends Controller
  7. {
  8. /**
  9. * Show the profile for the given user.
  10. */
  11. public function show(string $id): View
  12. {
  13. return view('user.profile', [
  14. 'user' => Redis::get('user:profile:'.$id)
  15. ]);
  16. }
  17. }

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

  1. use Illuminate\Support\Facades\Redis;
  2. Redis::set('name', 'Taylor');
  3. $values = Redis::lrange('names', 5, 10);

または、Redisファサードのcommandメソッドを使用してサーバーにコマンドを渡すこともできます。このメソッドは、最初の引数としてコマンドの名前を受け取り、2番目の引数として値の配列を受け取ります:

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

複数のRedis接続の使用

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

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

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

  1. $redis = Redis::connection();

トランザクション

  1. ``````php
  2. use Redis;
  3. use Illuminate\Support\Facades;
  4. Facades\Redis::transaction(function (Redis $redis) {
  5. $redis->incr('user_visits', 1);
  6. $redis->incr('total_visits', 1);
  7. });
  8. `

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

Luaスクリプト

  1. `````eval`````メソッドは最初は少し怖いかもしれませんが、基本的な例を探求して氷を破りましょう。`````eval`````メソッドは、いくつかの引数を期待します。最初に、Luaスクリプト(文字列として)をメソッドに渡す必要があります。次に、スクリプトが対話するキーの数(整数として)を渡す必要があります。3番目に、それらのキーの名前を渡す必要があります。最後に、スクリプト内でアクセスする必要がある他の追加の引数を渡すことができます。
  2. この例では、カウンターをインクリメントし、その新しい値を検査し、最初のカウンターの値が5より大きい場合に2番目のカウンターをインクリメントします。最後に、最初のカウンターの値を返します:
  3. ``````php
  4. $value = Redis::eval(<<<'LUA'
  5. local counter = redis.call("incr", KEYS[1])
  6. if counter > 5 then
  7. redis.call("incr", KEYS[2])
  8. end
  9. return counter
  10. LUA, 2, 'first-counter', 'second-counter');
  11. `

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

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

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

  1. use Redis;
  2. use Illuminate\Support\Facades;
  3. Facades\Redis::pipeline(function (Redis $pipe) {
  4. for ($i = 0; $i < 1000; $i++) {
  5. $pipe->set("key:$i", $i);
  6. }
  7. });

Pub / Sub

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

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

  1. <?php
  2. namespace App\Console\Commands;
  3. use Illuminate\Console\Command;
  4. use Illuminate\Support\Facades\Redis;
  5. class RedisSubscribe extends Command
  6. {
  7. /**
  8. * The name and signature of the console command.
  9. *
  10. * @var string
  11. */
  12. protected $signature = 'redis:subscribe';
  13. /**
  14. * The console command description.
  15. *
  16. * @var string
  17. */
  18. protected $description = 'Subscribe to a Redis channel';
  19. /**
  20. * Execute the console command.
  21. */
  22. public function handle(): void
  23. {
  24. Redis::subscribe(['test-channel'], function (string $message) {
  25. echo $message;
  26. });
  27. }
  28. }

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

  1. use Illuminate\Support\Facades\Redis;
  2. Route::get('/publish', function () {
  3. // ...
  4. Redis::publish('test-channel', json_encode([
  5. 'name' => 'Adam Wathan'
  6. ]));
  7. });

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

  1. ``````php
  2. Redis::psubscribe(['*'], function (string $message, string $channel) {
  3. echo $message;
  4. });
  5. Redis::psubscribe(['users.*'], function (string $message, string $channel) {
  6. echo $message;
  7. });
  8. `