Cache
Table of Contents
Introduction
あなたの application が実行する一部の data の取得や processing のタスクは、CPU を多大に負荷したり、完了までに数秒を要することがあります。このような場合、同じ data を後で素早く取得できるように、一時的に retrieved data を retrieved することが一般的です。 cache された data は、通常、Memcached や Redis のような非常に高速な data ストアに格納されます。
ありがたいことに、 Laravel は、さまざまな cache バックエンドに対する表現豊かで統一された API を提供しており、それらの驚くほど高速な data 取得を活用し、あなたの web application のスピードをアップさせることができます。
Configuration
あなたのアプリケーションの cache 設定ファイルはconfig/cache.phpに位置しています。このファイルで、あなたの application 全体で default で使用したい" cache ストアを指定することができます。 Laravel は、Memcached やRedis 、DynamoDB 、そしてリレーショナルデータベースといった一般的なキャッシュバックエンドをサポートしています。さらに、ファイルベースの" cache driver "が利用可能であり、arrayおよび"null"の cache ドライバーは、あなたの自動テストのための便利な cache バックエンドを提供します。
cache 設定ファイルには、ご確認いただける様々な他の options が含まれています。 default では、 Laravel はdatabase cache driver を使用するように設定されており、これはアプリケーションの database `にシリアライズされたキャッシュされたオブジェクトを保存します。
Driver の前提条件
Database
databaseの cache driver を使用する場合、cache data を含む database テーブルが必要になります。通常、これは Laravel の default 0001_01_01_000001_create_cache_table.php database migrationに含まれていますが、もし application にこのマイグレーションが含まれていない場合、 make:cache-tableの Artisan command を使用して作成することができます:
php artisan make:cache-table
php artisan migrate
Memcached
Memcached driver の使用には、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 ソケットの path に設定することができます。これを行う場合、portオプションは0に設定するべきです:
'memcached' => [
// ...
'servers' => [
[
'host' => '/var/run/memcached/memcached.sock',
'port' => 0,
'weight' => 100
],
],
],
Redis
Redis cache を Laravel で使用する前に、PECL 経由で PhpRedis PHP 拡張をインストールするか、 Composer 経由で predis/predis パッケージ(〜2.0)をインストールする必要があります。Laravel Sailはすでにこの拡張を含んでいます。また、Laravel Forge や Laravel Vapor などの公式 Laravel deployment プラットフォームには default で PhpRedis 拡張がインストールされています。
Redis の設定についての詳しい情報は、そのLaravel ドキュメンテーションページを参照してください。
DynamoDB
DynamoDB cache driver を使用する前に、cache した data をすべて保存するための DynamoDB テーブルを作成する必要があります。通常、このテーブルの名前は cache とすべきです。ただし、テーブルの名前は、 cache 設定ファイル内の stores.dynamodb.table 設定の value に基づいて名付けるべきです。また、テーブル名は DYNAMODB_CACHE_TABLE environment variables を通じて設定することも可能です。
このテーブルには、アプリケーションの cache 設定ファイル内の stores.dynamodb.attributes.key 設定項目の value に対応する名前を持つ string パーティションキーも含まれているべきです。 default によると、パーティションキーは key という名前であるべきです。
次に、あなたの Laravel application が DynamoDB と通信できるように、AWS SDK をインストールします:
composer require aws/aws-sdk-php
また、 DynamoDB cache ストア設定 options に values が提供されていることを確認する必要があります。通常、これらの options は、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 Usage
Cache インスタンスの取得
cache ストアインスタンスを取得するために、Cache facade を使用することができます。これは、このドキュメント全体で使用するものです。Cache facade は、Laravel cache contracts の基本実装に対して便利で簡潔なアクセスを提供します:
<?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 [
// ...
];
}
}
複数の Cache ストアへのアクセス
Cacheの facade を使用すると、storeの method を介してさまざまな cache ストアにアクセスできます。store method に渡すキーは、cache設定ファイル内のstores設定の array に記載されているストアのいずれかに対応する必要があります。
$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 600); // 10 Minutes
Cache からアイテムを取り出す
Cache facade の get method は、 cache からアイテムを取得するために使用されます。アイテムが cache 内に存在しない場合、null が返されます。 もし望むなら、get method に 2 つ目の引数を渡して、アイテムが存在しない場合に返されるべき default value を指定することができます:
$value = Cache::get('key');
$value = Cache::get('key', 'default');
あなたはクロージャを default value として渡すことさえできます。指定されたアイテムが cache に存在しない場合、クロージャの結果が返されます。クロージャを渡すことで、 database や他の外部 service からの default values の取得を遅らせることができます。
$value = Cache::get('key', function () {
return DB::table(/* ... */)->get();
});
アイテムの存在を確認する
has method は、アイテムが cache 内に存在するかどうかを判断するために使用できます。この method は、アイテムが存在するがその value がnullの場合もfalseを返します:
if (Cache::has('key')) {
// ...
}
Values の増分/減分
incrementおよびdecrementmethods は、 cache 内の integer 項目の value を調整するために使用できます。これらの両方の methods は、項目の value を increment またはデクリメントする金額を示す option の 2 つ目の引数を受け入れます。
// 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 からアイテムを取得したいと思うかもしれませんが、要求されたアイテムが存在しない場合には default value を保存したいと思うかもしれません。例えば、 cache から全ての users を取得したいと思うかもしれませんし、それらが存在しない場合には database からそれらを取得し、それらを cache に追加することもあります。これはCache::remember method を使用して行うことができます:
$value = Cache::remember('users', $seconds, function () {
return DB::table('users')->get();
});
もしアイテムが cache に存在しない場合、remember に渡されたクロージャは実行され、その結果は cache に配置されます。
rememberForever method を使用して、 cache からアイテムを取得したり、存在しない場合は永久に保存したりすることができます:
$value = Cache::rememberForever('users', function () {
return DB::table('users')->get();
});
取得し、 Delete
cache からアイテムを取り出し、そのアイテムを削除する必要がある場合は、pull method を使用することができます。get method のように、アイテムが cache に存在しない場合はnullが返されます。
$value = Cache::pull('key');
項目を Cache に保存する
put method を使用して、Cache facade に cache にアイテムを保存することができます:
Cache::put('key', 'value', $seconds = 10);
もしput method に storage 時間が渡されない場合、アイテムは無期限に保存されます:
Cache::put('key', 'value');
秒数を integer として渡す代わりに、キャッシュされたアイテムの期限切れ予定時間を表すDateTimeインスタンスを渡すこともできます。
Cache::put('key', 'value', now()->addMinutes(10));
存在しない場合は保存
add method は、アイテムが既に cache ストアに存在しない場合にのみ、アイテムを cache に追加します。 method は、アイテムが実際に cache に追加された場合はtrueを返します。それ以外の場合、 method はfalseを返します。add method はアトミック操作です:
Cache::add('key', 'value', $seconds);
アイテムを永遠に保存する
forever method は、アイテムを cache に永久に保存するために使用できます。これらのアイテムは期限切れにならないため、forget method を使用して手動で cache から削除する必要があります。
Cache::forever('key', 'value');
NOTE
Memcached driver を使用している場合、"永久に"保存されるアイテムは、 cache がそのサイズ制限に達したときに削除される可能性があります。
Cache からアイテムを削除する
forgetの method を使って cache からアイテムを削除することができます。
Cache::forget('key');
有効期限の秒数をゼロまたは負の数値で提供することにより、アイテムを削除することも可能です:
Cache::put('key', 'value', 0);
Cache::put('key', 'value', -5);
flush method を使用して、 cache をすべてクリアすることができます:
Cache::flush();
WARNING
cache のフラッシュは、設定した cache の"prefix"を尊重せず、 cache からすべてのエントリを削除します。他のアプリケーションと共有している cache をクリアする際には、これを慎重に考慮してください。
Cache ヘルパー
Cache facade を使用することに加えて、グローバルなcache関数を使用して、 cache 経由で data を取得および保存することもできます。 cache関数が single 、 string 引数で呼び出されると、指定された key の value を返します:
$value = cache('key');
もしあなたがキー/ value のペアの array と有効期限を関数に提供すると、それは指定された期間の間、 values を cache に保存します:
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();
});
NOTE
testing 中にグローバルな
cache関数を呼び出すと、facade の testingを行うかのようにCache::shouldReceivemethod を使用することができます。
Atomic Locks
WARNING
この feature を利用するために、あなたの application は、
memcached、redis、dynamodb、database、file、またはarrayの cache driver を、あなたのアプリケーションの default cache driver として使用する必要があります。さらに、すべてのサーバーは同じ中央の cache サーバーと通信している必要があります。
ロックの管理
アトミックロックにより、レース条件を気にせずに分散ロックを操作することができます。例えば、Laravel Forge はアトミックロックを使用して、一度に一つのリモートタスクのみがサーバー上で実行されることを保証します。Cache::lock method を使用して、ロックを作成および管理できます。
use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('foo', 10);
if ($lock->get()) {
// Lock acquired for 10 seconds...
$lock->release();
}
get method はクロージャも受け入れます。クロージャが実行された後、Laravel は自動的にロックを解除します:
Cache::lock('foo', 10)->get(function () {
// Lock acquired for 10 seconds and automatically released...
});
ロックが現時点で利用できない場合、 request を行う際に、 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 method に渡すことで単純化できます。クロージャがこの method に渡されると、 Laravel は指定された秒数だけロックの取得を attempt し、クロージャが実行されると自動的にロックを release します。
Cache::lock('foo', 10)->block(5, function () {
// Lock acquired after waiting a maximum of 5 seconds...
});
プロセス間でのロックの管理
時々、一つの process でロックを取得し、別の process でそれを release したい場合があるでしょう。例えば、web request の間にロックを取得し、その request によってトリガーされる queue に入った job の終了時にロックを release したいと思うかもしれません。このシナリオでは、ロックの範囲に"owner token"を queue に入れた job に渡すべきで、そのために job は与えられた token を使ってロックを再インスタンス化できます。
以下の例では、ロックが正常に取得された場合、キューに入れられた job を dispatch します。さらに、ロックの owner method を介してキューに入れられた job にロックの所有者の token を渡します。
$podcast = Podcast::find($id);
$lock = Cache::lock('processing', 120);
if ($lock->get()) {
ProcessPodcast::dispatch($podcast, $lock->owner());
}
私たちの application のProcessPodcast job の中で、所有者の token を使ってロックを復元及び解放することができます。
Cache::restoreLock('processing', $this->owner)->release();
現在の所有者を尊重せずに release したい場合は、forceRelease method を使用できます:
Cache::lock('processing')->forceRelease();
Adding Custom Cache Drivers
Driver の作成
私たちの custom cache driver を作成するためには、まず Illuminate\Contracts\Cache\Store contractを実装する必要があります。そのため、MongoDB の cache 実装は次のようになるかもしれません:
<?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() {}
}
これらの method を MongoDB の connection を使って実装する必要があります。これらの method をどのように実装するかの例については、Laravel framework source code の Illuminate\Cache\MemcachedStore を参照してください。実装が完了したら、Cache facade の extend method を呼び出して custom driver の登録を完了できます。
Cache::extend('mongo', function (Application $app) {
return Cache::repository(new MongoStore);
});
NOTE
もし custom cache driver code をどこに配置すればいいか疑問に思っているなら、
appディレクトリ内にExtensionsという名前空間を作成することができます。ただし、 Laravel は厳密な application の構造を持っていないことと、あなたが自由に自分の application を整理することができるということを覚えておいてください。
Driver の登録
Laravel で custom cache driver を register するために、Cache facade のextend method を使用します。他の service providers がboot method 内でキャッシュされた values を attempt する可能性があるため、bootingコールバック内で custom driver を register します。bootingコールバックを使用することで、アプリケーションの service providers のboot method が呼び出される直前に custom driver が登録され、すべての service providers のregister method が呼び出された後になることを保証できます。bootingコールバックは、アプリケーションのApp\Providers\AppServiceProvider class のregister method 内で register します:
<?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
{
// ...
}
}
extend method に渡される最初の引数は、 driver の名前です。これはconfig/cache.php設定ファイル内のdriveroption に対応します。二番目の引数は、Illuminate\Cache\Repositoryインスタンスを返すべきクロージャーです。クロージャーには、service containerのインスタンスである$appインスタンスが渡されます。
あなたの拡張機能が登録されたら、CACHE_STORE 環境 variable を更新するか、application のconfig/cache.php設定ファイル内のdefaultoption を、あなたの拡張機能の名前に変更してください。
Events
cache の各操作で code を実行するには、 cache から発行されるさまざまな events をリッスンすることができます。
| Event Name |
|---|
Illuminate\Cache\Events\CacheHit |
Illuminate\Cache\Events\CacheMissed |
Illuminate\Cache\Events\KeyForgotten |
Illuminate\Cache\Events\KeyWritten |
パフォーマンスを向上させるために、events設定オプションをアプリケーションのconfig/cache.php設定ファイル内の特定の cache ストアでfalseに設定することにより、 cache events を無効にすることができます。
'database' => [
'driver' => 'database',
// ...
'events' => false,
],