コンテンツへスキップ

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' => [
'url' => 'tls://user:[email protected]: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'),
],
],
],
 
// ...
],

デフォルトでは、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は、namepersistentpersistent_idprefixread_timeoutretry_intervaltimeoutcontextの追加の接続パラメータをサポートしています。これらのオプションのいずれかを、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_PHPRedis::SERIALIZER_JSONRedis::SERIALIZER_IGBINARYRedis::SERIALIZER_MSGPACKが含まれます。

サポートされている圧縮アルゴリズムには、Redis::COMPRESSION_NONE(デフォルト)、Redis::COMPRESSION_LZFRedis::COMPRESSION_ZSTDRedis::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);
});
exclamation

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 counter
LUA, 2, 'first-counter', 'second-counter');
exclamation

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のpublishsubscribeコマンドへの便利なインターフェースを提供しています。これらの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;
});