はじめに
アプリケーションが実行するデータ取得や処理タスクの中には、CPU集約型であったり、完了するまでに数秒かかるものがあります。このような場合、同じデータに対する後続のリクエストで迅速に取得できるように、取得したデータを一定期間キャッシュすることが一般的です。キャッシュされたデータは通常、MemcachedやRedisのような非常に高速なデータストアに保存されます。
幸いなことに、Laravelはさまざまなキャッシュバックエンドに対して表現力豊かで統一されたAPIを提供しており、これにより、驚異的に高速なデータ取得を活用してWebアプリケーションの速度を向上させることができます。
設定
アプリケーションのキャッシュ設定ファイルはconfig/cache.php
にあります。このファイルでは、アプリケーション全体でデフォルトとして使用するキャッシュストアを指定できます。Laravelは、Memcached、Redis、DynamoDB、およびリレーショナルデータベースなどの人気のあるキャッシングバックエンドを標準でサポートしています。さらに、ファイルベースのキャッシュドライバーも利用可能で、array
および「null」キャッシュドライバーは、自動化テスト用の便利なキャッシュバックエンドを提供します。
キャッシュ設定ファイルには、他にもさまざまなオプションが含まれており、確認することができます。デフォルトでは、Laravelはdatabase
キャッシュドライバーを使用するように設定されており、これはアプリケーションのデータベースにシリアライズされたキャッシュオブジェクトを保存します。
ドライバの前提条件
データベース
database
キャッシュドライバーを使用する場合、キャッシュデータを格納するためのデータベーステーブルが必要です。通常、これはLaravelのデフォルトの0001_01_01_000001_create_cache_table.php
データベースマイグレーションに含まれています。ただし、アプリケーションにこのマイグレーションが含まれていない場合は、make:cache-table
Artisanコマンドを使用して作成できます:
php artisan make:cache-table
php artisan migrate
Memcached
Memcachedドライバーを使用するには、Memcached PECLパッケージをインストールする必要があります。config/cache.php
設定ファイルにすべてのMemcachedサーバーをリストすることができます。このファイルには、開始するためのmemcached.servers
エントリがすでに含まれています:
'memcached' => [
// ...
'servers' => [
[
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
'port' => env('MEMCACHED_PORT', 11211),
'weight' => 100,
],
],
],
必要に応じて、host
オプションをUNIXソケットパスに設定できます。この場合、port
オプションは0
に設定する必要があります:
'memcached' => [
// ...
'servers' => [
[
'host' => '/var/run/memcached/memcached.sock',
'port' => 0,
'weight' => 100
],
],
],
Redis
LaravelでRedisキャッシュを使用する前に、PECL経由でPhpRedis PHP拡張をインストールするか、Composerを介してpredis/predis
パッケージ(~2.0)をインストールする必要があります。Laravel Sailには、この拡張がすでに含まれています。さらに、Laravel ForgeやLaravel Vaporなどの公式Laravelデプロイメントプラットフォームには、PhpRedis拡張がデフォルトでインストールされています。
Redisの設定に関する詳細は、Laravelのドキュメントページを参照してください。
DynamoDB
https://aws.amazon.com/dynamodbキャッシュドライバーを使用する前に、すべてのキャッシュデータを格納するためのDynamoDBテーブルを作成する必要があります。通常、このテーブルはcache
という名前にする必要があります。ただし、cache
設定ファイル内のstores.dynamodb.table
設定値に基づいてテーブルの名前を付けるべきです。テーブル名はDYNAMODB_CACHE_TABLE
環境変数を介して設定することもできます。
このテーブルには、アプリケーションのcache
設定ファイル内のstores.dynamodb.attributes.key
設定項目の値に対応する名前の文字列パーティションキーも必要です。デフォルトでは、パーティションキーはkey
という名前になります。
通常、DynamoDBはテーブルから期限切れのアイテムを自動的に削除しません。したがって、テーブルでTime to Live (TTL)を有効にする必要があります。テーブルのTTL設定を構成する際は、TTL属性名をexpires_at
に設定する必要があります。
次に、AWS SDKをインストールして、LaravelアプリケーションがDynamoDBと通信できるようにします:
composer require aws/aws-sdk-php
さらに、DynamoDBキャッシュストア設定オプションに値が提供されていることを確認する必要があります。通常、AWS_ACCESS_KEY_ID
やAWS_SECRET_ACCESS_KEY
などのオプションは、アプリケーションの.env
設定ファイルに定義されるべきです:
'dynamodb' => [
'driver' => 'dynamodb',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
'endpoint' => env('DYNAMODB_ENDPOINT'),
],
キャッシュの使用
キャッシュインスタンスの取得
キャッシュストアインスタンスを取得するには、Cache
ファサードを使用できます。これは、このドキュメント全体で使用するものです。Cache
ファサードは、Laravelキャッシュ契約の基盤となる実装への便利で簡潔なアクセスを提供します:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
class UserController extends Controller
{
/**
* Show a list of all users of the application.
*/
public function index(): array
{
$value = Cache::get('key');
return [
// ...
];
}
}
複数のキャッシュストアへのアクセス
``````php
$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 600); // 10 Minutes
`
キャッシュからのアイテムの取得
``````php
$value = Cache::get('key');
$value = Cache::get('key', 'default');
`
デフォルト値としてクロージャを渡すこともできます。指定されたアイテムがキャッシュに存在しない場合、クロージャの結果が返されます。クロージャを渡すことで、デフォルト値の取得をデータベースや他の外部サービスから遅延させることができます:
$value = Cache::get('key', function () {
return DB::table(/* ... */)->get();
});
アイテムの存在確認
``````php
if (Cache::has('key')) {
// ...
}
`
値のインクリメント / デクリメント
``````php
// Initialize the value if it does not exist...
Cache::add('key', 0, now()->addHours(4));
// Increment or decrement the value...
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);
`
取得と保存
時には、キャッシュからアイテムを取得したいが、要求されたアイテムが存在しない場合にデフォルト値を保存したいことがあります。たとえば、キャッシュからすべてのユーザーを取得したい場合、存在しない場合はデータベースから取得してキャッシュに追加することができます。これをCache::remember
メソッドを使用して行うことができます:
$value = Cache::remember('users', $seconds, function () {
return DB::table('users')->get();
});
アイテムがキャッシュに存在しない場合、remember
メソッドに渡されたクロージャが実行され、その結果がキャッシュに格納されます。
``````php
$value = Cache::rememberForever('users', function () {
return DB::table('users')->get();
});
`
再検証中の古いデータの提供
この柔軟なメソッドは、キャッシュされた値が「新鮮」と見なされる時間と「古い」と見なされる時間を指定する配列を受け取ります。配列の最初の値は、キャッシュが新鮮と見なされる秒数を表し、2番目の値は再計算が必要になる前に古いデータとして提供できる時間を定義します。
新鮮な期間内(最初の値の前)にリクエストが行われた場合、キャッシュは再計算なしですぐに返されます。古い期間中(2つの値の間)にリクエストが行われた場合、古い値がユーザーに提供され、[遅延関数](18a7b2a8da62b09e.md#deferred-functions)がユーザーへの応答が送信された後にキャッシュされた値を更新するために登録されます。2番目の値の後にリクエストが行われた場合、キャッシュは期限切れと見なされ、値は即座に再計算され、ユーザーにとって遅い応答が発生する可能性があります:
``````php
$value = Cache::flexible('users', [5, 10], function () {
return DB::table('users')->get();
});
`
取得と削除
キャッシュからアイテムを取得して削除する必要がある場合、pull
メソッドを使用できます。get
メソッドと同様に、アイテムがキャッシュに存在しない場合はnull
が返されます:
$value = Cache::pull('key');
$value = Cache::pull('key', 'default');
キャッシュにアイテムを保存
``````php
Cache::put('key', 'value', $seconds = 10);
`
ストレージ時間がput
メソッドに渡されない場合、アイテムは無期限に保存されます:
Cache::put('key', 'value');
整数として秒数を渡す代わりに、キャッシュアイテムの希望する有効期限を表すDateTime
インスタンスを渡すこともできます:
Cache::put('key', 'value', now()->addMinutes(10));
存在しない場合に保存
``````php
Cache::add('key', 'value', $seconds);
`
アイテムを永遠に保存
``````php
Cache::forever('key', 'value');
`
Memcachedドライバーを使用している場合、「永遠に」保存されたアイテムは、キャッシュがサイズ制限に達したときに削除される可能性があります。
キャッシュからアイテムを削除
``````php
Cache::forget('key');
`
ゼロまたは負の有効期限秒数を指定することでアイテムを削除することもできます:
Cache::put('key', 'value', 0);
Cache::put('key', 'value', -5);
``````php
Cache::flush();
`
キャッシュをフラッシュすると、設定されたキャッシュ「プレフィックス」を尊重せず、キャッシュからすべてのエントリが削除されます。他のアプリケーションと共有されているキャッシュをクリアする際は、これを慎重に考慮してください。
キャッシュヘルパー
``````php
$value = cache('key');
`
キー/値ペアの配列と有効期限を関数に提供すると、指定された期間キャッシュに値が保存されます:
cache(['key' => 'value'], $seconds);
cache(['key' => 'value'], now()->addMinutes(10));
引数なしでcache
関数が呼び出されると、Illuminate\Contracts\Cache\Factory
実装のインスタンスが返され、他のキャッシングメソッドを呼び出すことができます:
cache()->remember('users', $seconds, function () {
return DB::table('users')->get();
});
グローバルcache
関数への呼び出しをテストする際は、ファサードをテストするのと同様にCache::shouldReceive
メソッドを使用できます。
原子的ロック
この機能を利用するには、アプリケーションがmemcached
、redis
、dynamodb
、database
、file
、またはarray
キャッシュドライバーをデフォルトのキャッシュドライバーとして使用している必要があります。さらに、すべてのサーバーが同じ中央キャッシュサーバーと通信している必要があります。
ロックの管理
原子的ロックを使用すると、競合状態を心配することなく分散ロックを操作できます。たとえば、Laravel Forgeは、サーバー上で同時に1つのリモートタスクのみが実行されることを保証するために原子的ロックを使用します。Cache::lock
メソッドを使用してロックを作成および管理できます:
use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('foo', 10);
if ($lock->get()) {
// Lock acquired for 10 seconds...
$lock->release();
}
``````php
Cache::lock('foo', 10)->get(function () {
// Lock acquired for 10 seconds and automatically released...
});
`
ロックが要求した時点で利用できない場合、Laravelに指定された秒数待機するよう指示できます。指定された時間内にロックを取得できない場合、Illuminate\Contracts\Cache\LockTimeoutException
がスローされます:
use Illuminate\Contracts\Cache\LockTimeoutException;
$lock = Cache::lock('foo', 10);
try {
$lock->block(5);
// Lock acquired after waiting a maximum of 5 seconds...
} catch (LockTimeoutException $e) {
// Unable to acquire lock...
} finally {
$lock->release();
}
上記の例は、block
メソッドにクロージャを渡すことで簡略化できます。このメソッドにクロージャを渡すと、Laravelは指定された秒数ロックを取得し、クロージャが実行された後に自動的にロックを解放します:
Cache::lock('foo', 10)->block(5, function () {
// Lock acquired after waiting a maximum of 5 seconds...
});
プロセス間のロックの管理
時には、1つのプロセスでロックを取得し、別のプロセスでそれを解放したいことがあります。たとえば、Webリクエスト中にロックを取得し、そのリクエストによってトリガーされたキューイングされたジョブの終了時にロックを解放したい場合です。このシナリオでは、ロックのスコープされた「オーナートークン」をキューイングされたジョブに渡す必要があります。
以下の例では、ロックが正常に取得された場合にキューイングされたジョブをディスパッチします。さらに、ロックのオーナートークンをロックのowner
メソッドを介してキューイングされたジョブに渡します:
$podcast = Podcast::find($id);
$lock = Cache::lock('processing', 120);
if ($lock->get()) {
ProcessPodcast::dispatch($podcast, $lock->owner());
}
アプリケーションのProcessPodcast
ジョブ内で、オーナートークンを使用してロックを復元および解放できます:
Cache::restoreLock('processing', $this->owner)->release();
現在のオーナーを尊重せずにロックを解放したい場合は、forceRelease
メソッドを使用できます:
Cache::lock('processing')->forceRelease();
カスタムキャッシュドライバーの追加
ドライバーの作成
カスタムキャッシュドライバーを作成するには、まずIlluminate\Contracts\Cache\Store
契約を実装する必要があります。したがって、MongoDBキャッシュの実装は次のようになります:
<?php
namespace App\Extensions;
use Illuminate\Contracts\Cache\Store;
class MongoStore implements Store
{
public function get($key) {}
public function many(array $keys) {}
public function put($key, $value, $seconds) {}
public function putMany(array $values, $seconds) {}
public function increment($key, $value = 1) {}
public function decrement($key, $value = 1) {}
public function forever($key, $value) {}
public function forget($key) {}
public function flush() {}
public function getPrefix() {}
}
これらのメソッドをMongoDB接続を使用して実装するだけです。これらのメソッドの実装方法の例については、LaravelフレームワークのソースコードのIlluminate\Cache\MemcachedStore
を参照してください。実装が完了したら、Cache
ファサードのextend
メソッドを呼び出してカスタムドライバーの登録を完了できます:
Cache::extend('mongo', function (Application $app) {
return Cache::repository(new MongoStore);
});
カスタムキャッシュドライバーコードをどこに置くか疑問に思っている場合は、app
ディレクトリ内にExtensions
名前空間を作成できます。ただし、Laravelには厳密なアプリケーション構造がないため、好みに応じてアプリケーションを整理することができます。
ドライバーの登録
Laravelにカスタムキャッシュドライバーを登録するには、Cache
ファサードのextend
メソッドを使用します。他のサービスプロバイダーがboot
メソッド内でキャッシュされた値を読み取ろうとする可能性があるため、booting
コールバック内でカスタムドライバーを登録します。booting
コールバックを使用することで、アプリケーションのサービスプロバイダーでboot
メソッドが呼び出される直前にカスタムドライバーが登録されることを保証できますが、すべてのサービスプロバイダーでregister
メソッドが呼び出された後です。アプリケーションのApp\Providers\AppServiceProvider
クラスのregister
メソッド内でbooting
コールバックを登録します:
<?php
namespace App\Providers;
use App\Extensions\MongoStore;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
$this->app->booting(function () {
Cache::extend('mongo', function (Application $app) {
return Cache::repository(new MongoStore);
});
});
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
// ...
}
}
拡張機能が登録されたら、アプリケーションの`````config/cache.php`````設定ファイル内の`````CACHE_STORE`````環境変数または`````default`````オプションを拡張機能の名前に更新します。
<a name="events"></a>
## イベント
キャッシュ操作ごとにコードを実行するには、キャッシュによって発行されたさまざまな[イベント](/read/laravel-11-x/2fd66143d78d4ae2.md)をリッスンできます:
| イベント名 |
| --- |
| `````Illuminate\Cache\Events\CacheHit````` |
| `````Illuminate\Cache\Events\CacheMissed````` |
| `````Illuminate\Cache\Events\KeyForgotten````` |
| `````Illuminate\Cache\Events\KeyWritten````` |
パフォーマンスを向上させるために、アプリケーションの`````config/cache.php`````設定ファイル内の特定のキャッシュストアに対して`````events`````設定オプションを`````false`````に設定することでキャッシュイベントを無効にできます:
``````php
'database' => [
'driver' => 'database',
// ...
'events' => false,
],
`