Кэширование
- Введение
- Конфигурирование
- Предварительная подготовка драйверов
- Управление кешем приложения
- Получение экземпляра кеша
- Получение элементов из кеша
- Сохранение элементов в кеше
- Продление времени жизни элемента
- Удаление элементов из кеша
- Кэширование с использованием мемоизации
- Глобальный помощник кеша
- Теги кеша
- Сохранение элементов кеша с тегами
- Получение элементов кеша с тегами
- Удаление элементов кеша с тегами
- Атомарные блокировки
- Управление блокировками
- Управление блокировками между процессами
- Обновление блокировок
- Ограничение конкурентного выполнения
- Failover кеша
- Добавление собственных драйверов кеша
- Написание драйвера кеша
- Регистрация драйвера кеша
- События
Введение
Некоторые задачи по извлечению или обработке данных, выполняемые вашим приложением, могут потребовать больших ресурсов ЦП или занять несколько секунд. В этом случае извлеченные данные обычно кешируют на некоторое время, чтобы их можно было быстро извлечь при последующих запросах тех же данных. Кешированные данные обычно хранятся в хранилище с быстрым доступом данных, например, Memcached или Redis.
К счастью, Laravel предлагает выразительный унифицированный API для различных серверов кеширования, позволяя вам воспользоваться их невероятно быстрым извлечением данных и ускорить работу вашего веб-приложения.
Конфигурирование
Файл конфигурации кеша вашего приложения находится в config/cache.php. В этом файле вы можете указать, какое хранилище кеша вы хотите использовать по умолчанию во всем приложении. Laravel из коробки поддерживает популярные механизмы кеширования, такие как Memcached, Redis, DynamoDB, реляционные базы данных и диски файловой системы. Кроме того, доступен драйвер кеширования на основе файлов, в то время как драйверы array и null предоставляют удобные механизмы кеширования для ваших автоматических тестов.
Файл конфигурации кэша также содержит множество других параметров, которые вы можете просмотреть. По умолчанию Laravel настроен на использование драйвера кэша database, который сохраняет сериализованные кэшированные объекты в базе данных вашего приложения.
Предварительная подготовка драйверов
Предварительная подготовка драйвера на основе базы данных
При использовании драйвера кэша database вам понадобится таблица базы данных, содержащая данные кэша. Обычно это включено в стандартный файл Laravel 0001_01_01_000001_create_cache_table.php миграции базы данных; однако, если ваше приложение не содержит этой миграции, вы можете использовать Artisan-команду make:cache-table для ее создания:
php artisan make:cache-table
php artisan migrate
Предварительная подготовка драйвера на основе Memcached
Для использования драйвера Memcached требуется установить пакет Memcached PECL. Вы можете перечислить все ваши серверы Memcached в файле конфигурации config/cache.php. Этот файл уже содержит запись 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
Перед использованием драйвера кеша Redis, вам нужно будет либо установить расширение PHP PhpRedis через PECL, либо установить пакет predis/predis (~ 2.0) через Composer. Laravel Sail уже включает это расширение. Кроме того, на официальных платформах приложений Laravel, таких как Laravel Cloud и Laravel Forge, расширение PhpRedis установлено по умолчанию.
Для получения дополнительной информации о настройке Redis обратитесь к документации Laravel по Redis.
Хранилище
Драйвер кеша storage позволяет хранить кешированные значения на любом настроенном диске файловой системы вашего приложения. Это может быть полезно, если вы хотите использовать существующий диск, например S3-диск, как key / value-хранилище кеша:
'storage' => [
'driver' => 'storage',
'disk' => env('CACHE_STORAGE_DISK'),
'path' => env('CACHE_STORAGE_PATH', 'framework/cache/data'),
],
Предварительная подготовка драйвера на основе DynamoDB
Перед использованием драйвера кэша DynamoDB необходимо создать таблицу DynamoDB для хранения всех кэшированных данных. Обычно это cache. Название таблицы должно совпадать с stores.dynamodb.table в конфигурационном файле cache. Имя таблицы также можно задать с помощью переменной среды DYNAMODB_CACHE_TABLE.
Эта таблица также должна иметь строковый ключ раздела с именем, соответствующим значению элемента конфигурации stores.dynamodb.attributes.key в конфигурационном файле cache. По умолчанию это 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'),
],
MongoDB
Если вы используете MongoDB, драйвер кэша mongodb предоставляется официальным пакетом mongodb/laravel-mongodb и может быть настроен с помощью подключения к базе данных mongodb. MongoDB поддерживает индексы TTL, которые можно использовать для автоматической очистки элементов кэша с истекшим сроком действия.
Для получения дополнительной информации о настройке MongoDB обратитесь к документации по кэшу и блокировкам MongoDB.
Управление кешем приложения
Получение экземпляра кеша
Чтобы получить экземпляр хранилища кеша, вы можете использовать фасад Cache, который мы будем использовать в этой документации. Фасад Cache обеспечивает удобный и краткий доступ к базовым реализациям контрактов кеширования Laravel:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
class UserController extends Controller
{
/**
* Показать список всех пользователей приложения.
*/
public function index(): array
{
$value = Cache::get('key');
return [
// ...
];
}
}
Доступ к различным кеш-хранилищам
Используя фасад Cache, вы можете получить доступ к различным хранилищам кеша с помощью метода store. Ключ, переданный методу store, должен соответствовать одному из хранилищ, перечисленных в массиве stores вашего конфигурационного файла config/cache.php:
$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 600); // 10 Минут
Получение элементов из кеша
Метод get фасада Cache используется для извлечения элементов из кеша. Если элемент не существует в кеше, будет возвращено значение null. Если хотите, то вы можете передать второй аргумент методу get, указав значение по умолчанию, которое вы хотите вернуть, если элемент отсутствует:
$value = Cache::get('key');
$value = Cache::get('key', 'default');
Вы даже можете передать замыкание в качестве значения по умолчанию. Результат замыкания будет возвращен, если указанный элемент не существует в кеше. Передача замыкания позволяет отложить получение значений по умолчанию из базы данных или другой внешней службы:
$value = Cache::get('key', function () {
return DB::table(/* ... */)->get();
});
Проверка наличия элемента
Метод has используется для определения того, существует ли элемент в кеше. Этот метод также вернет false, если элемент существует, но его значение равно null:
if (Cache::has('key')) {
// ...
}
Увеличение и уменьшение отдельных значений в кеше
Методы increment и decrement могут использоваться для изменения значений целочисленных элементов в кеше. Оба метода принимают необязательный второй аргумент, указывающий величину увеличения или уменьшения значения элемента:
// Инициализируем значение, если оно не существует...
Cache::add('key', 0, now()->addHours(4));
// Увеличиваем или уменьшаем значение...
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, будет выполнено, и его результат будет помещен в кеш.
Если вам нужно узнать, был ли элемент получен из кеша, а не путем выполнения переданного замыкания, вы можете использовать метод rememberWithWarmth. Этот метод возвращает массив, содержащий кешированное значение и булево значение, указывающее, был ли элемент «warm», то есть получен из кеша, а не вычислен замыканием:
[$value, $warm] = Cache::rememberWithWarmth('users', $seconds, function () {
return DB::table('users')->get();
});
Вы можете использовать метод rememberForever, чтобы получить элемент из кеша или сохранить его навсегда, если он не существует:
$value = Cache::rememberForever('users', function () {
return DB::table('users')->get();
});
Устарело при повторной проверке
При использовании метода Cache::remember у некоторых пользователей может наблюдаться медленное время отклика, если срок действия кэшированного значения истек. Для определенных типов данных может быть полезно разрешить обслуживание частично устаревших данных во время пересчета кэшированного значения в фоновом режиме, чтобы у некоторых пользователей не возникало медленного ответа во время расчета кэшированных значений. Это часто называют шаблоном «устаревшего при повторной проверке» (“stale-while-revalidate”), и метод Cache::flexible обеспечивает реализацию этого шаблона.
Гибкий метод принимает массив, который определяет, как долго кэшированное значение считается «свежим», а когда оно становится «устаревшим». Первое значение в массиве представляет количество секунд, в течение которых кеш считается свежим, а второе значение определяет, как долго он может использоваться как устаревшие данные, прежде чем потребуется пересчет.
Если запрос сделан в свежем периоде (до первого значения), кэш возвращается сразу без пересчета. Если запрос сделан в течение периода устаревания (между двумя значениями), устаревшее значение передается пользователю, и отложенная функция регистрируется в обновить кэшированное значение после отправки ответа пользователю. Если запрос сделан после второго значения, кеш считается просроченным, и значение немедленно пересчитывается, что может привести к более медленному ответу пользователя:
$value = Cache::flexible('users', [5, 10], function () {
return DB::table('users')->get();
});
Получение данных с последующим удалением элемента
Если вам нужно получить элемент из кеша, а затем удалить этот элемент, вы можете использовать метод pull. Как и в методе get, если элемент не существует в кеше, то будет возвращен null:
$value = Cache::pull('key');
$value = Cache::pull('key', 'default');
Сохранение элементов в кеше
Вы можете использовать метод put фасада Cache для сохранения элементов в кеше:
Cache::put('key', 'value', $seconds = 10);
Если время хранения не передается методу put, то элемент будет храниться бесконечно:
Cache::put('key', 'value');
Вместо того чтобы передавать количество секунд как целое число, вы также можете передать экземпляр DateTime, представляющий желаемое время хранения кешированного элемента:
Cache::put('key', 'value', now()->addMinutes(10));
Сохранение значений при условии их отсутствия
Метод add добавит элемент в кеш, только если он еще не существует в хранилище кеша. Метод вернет true, если элемент был действительно добавлен в кеш. В противном случае метод вернет false. Метод add – это атомарная операция:
Cache::add('key', 'value', $seconds);
Продление времени жизни элемента
Метод touch позволяет продлить время жизни (TTL) существующего элемента кеша. Метод touch вернет true, если элемент кеша существует и срок его действия был успешно продлен. Если элемент отсутствует в кеше, метод вернет false:
Cache::touch('key', 3600);
Вы можете передать экземпляр DateTimeInterface, DateInterval или Carbon, чтобы указать точное время истечения срока действия:
Cache::touch('key', now()->addHours(2));
Сохранение элементов на постоянной основе
Метод forever используется для постоянного хранения элемента в кеше. Поскольку срок действия этих элементов не истекает, то их необходимо вручную удалить из кеша с помощью метода forget:
Cache::forever('key', 'value');
Если вы используете драйвер
memcached, то элементы, которые хранятся «на постоянной основе», могут быть удалены, когда кеш достигнет предельного размера.
Удаление элементов из кеша
Вы можете удалить элементы из кеша с помощью метода forget:
Cache::forget('key');
Вы также можете удалить элементы, указав нулевое или отрицательное количество секунд срока хранения:
Cache::put('key', 'value', 0);
Cache::put('key', 'value', -5);
Вы можете очистить весь кеш, используя метод flush:
Cache::flush();
Вы можете очистить все атомарные блокировки в кеше с помощью метода flushLocks:
Cache::flushLocks();
Очистка кеша не учитывает ваш настроенный «префикс» кеша и удаляет все записи из кеша. Внимательно учитывайте это при очистке кеша, который используется другими приложениями.
Кэширование с использованием мемоизации
Драйвер кэша memo в Laravel позволяет временно сохранять полученные значения кэша в памяти во время обработки одного запроса или выполнения задачи. Это предотвращает повторные обращения к кэшу в рамках одного выполнения и значительно повышает производительность.
Чтобы использовать мемоизированный кэш, вызовите метод memo:
use Illuminate\Support\Facades\Cache;
$value = Cache::memo()->get('key');
Метод memo опционально принимает имя хранилища кэша, которое указывает базовое хранилище кэша, которое будет декорировать мемоизированный драйвер:
// Using the default cache store...
$value = Cache::memo()->get('key');
// Using the Redis cache store...
$value = Cache::memo('redis')->get('key');
Первый вызов get для заданного ключа извлекает значение из вашего кэш-хранилища, но последующие вызовы в том же запросе или задании будут извлекать значение из памяти:
// Hits the cache...
$value = Cache::memo()->get('key');
// Does not hit the cache, returns memoized value...
$value = Cache::memo()->get('key');
При вызове методов, которые изменяют значения кэша (например, put, increment, remember и т. д.), мемоизированный кэш автоматически забывает мемоизированное значение и делегирует вызов изменяющего метода базовому хранилищу кэша:
Cache::memo()->put('name', 'Taylor'); // Writes to underlying cache...
Cache::memo()->get('name'); // Hits underlying cache...
Cache::memo()->get('name'); // Memoized, does not hit cache...
Cache::memo()->put('name', 'Tim'); // Forgets memoized value, writes new value...
Cache::memo()->get('name'); // Hits underlying cache again...
Глобальный помощник кеша
Помимо использования фасада Cache, вы также можете использовать глобальную функцию cache для извлечения и хранения данных через кеш. Когда функция cache вызывается с одним строковым аргументом, она возвращает значение переданного ключа:
$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так же, как если бы вы тестировали фасад.
Теги кеша
Теги кеша не поддерживаются при использовании драйверов кеша
file,dynamodb,databaseилиstorage.
Сохранение элементов кеша с тегами
Теги кеша позволяют помечать связанные элементы кеша и затем очищать все кешированные значения, которым назначен определенный тег. Вы можете получить доступ к кешу с тегами, передав упорядоченный массив имен тегов. Например, получим tagged cache и поместим значение в кеш:
use Illuminate\Support\Facades\Cache;
Cache::tags(['people', 'artists'])->put('John', $john, $seconds);
Cache::tags(['people', 'authors'])->put('Anne', $anne, $seconds);
Получение элементов кеша с тегами
Элементы, сохраненные с тегами, нельзя получить без указания тех же тегов, которые использовались при сохранении значения. Чтобы получить элемент tagged cache, передайте тот же упорядоченный список тегов в метод tags, а затем вызовите метод get с нужным ключом:
$john = Cache::tags(['people', 'artists'])->get('John');
$anne = Cache::tags(['people', 'authors'])->get('Anne');
Удаление элементов кеша с тегами
Вы можете очистить все элементы, которым назначен тег или список тегов. Например, следующий код удалит весь кеш, помеченный тегом people, authors или обоими тегами. Поэтому из кеша будут удалены и Anne, и John:
Cache::tags(['people', 'authors'])->flush();
В отличие от этого, приведенный ниже код удалит только кешированные значения, помеченные тегом authors; поэтому Anne будет удалена, а John – нет:
Cache::tags('authors')->flush();
Атомарные блокировки
Чтобы использовать этот функционал, ваше приложение должно использовать драйвер кеша
memcached,redis,dynamodb,database,file, илиarrayв качестве драйвера кеша по умолчанию для вашего приложения. Кроме того, все серверы должны взаимодействовать с одним и тем же центральным сервером кеширования.
Управление блокировками
Атомарные блокировки позволяют управлять распределенными блокировками, не беспокоясь об условиях приоритетности. Например, Laravel Cloud использует атомарные блокировки, чтобы гарантировать, что на сервере одновременно выполняется только одна удаленная задача. Вы можете создавать и управлять блокировками, используя метод Cache::lock:
use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('foo', 10);
if ($lock->get()) {
// Блокировка получена на 10 секунд...
$lock->release();
}
Метод get также принимает замыкание. После выполнения замыкания Laravel автоматически снимет блокировку:
Cache::lock('foo', 10)->get(function () {
// Блокировка установлена на 10 секунд и автоматически снимается...
});
Если блокировка недоступна в тот момент, когда вы ее запрашиваете, вы можете указать Laravel подождать определенное количество секунд. Если блокировка не может быть получена в течение указанного срока, то будет выброшено исключение Illuminate\Contracts\Cache\LockTimeoutException:
use Illuminate\Contracts\Cache\LockTimeoutException;
$lock = Cache::lock('foo', 10);
try {
$lock->block(5);
// Блокировка получена после ожидания максимум 5 секунд...
} catch (LockTimeoutException $e) {
// Невозможно получить блокировку...
} finally {
$lock->release();
}
Приведенный выше пример можно упростить, передав замыкание методу block. Когда замыкание передается этому методу, Laravel будет пытаться получить блокировку на указанное количество секунд и автоматически снимет блокировку, как только замыкание будет выполнено:
Cache::lock('foo', 10)->block(5, function () {
// Блокировка получена после ожидания максимум 5 секунд...
});
Управление блокировками между процессами
Иногда может потребоваться установить блокировку в одном процессе и снять ее в другом процессе. Например, вы можете получить блокировку во время веб-запроса и захотите снять блокировку в конце задания в очереди, которое запускается этим запросом. В этом сценарии вы должны передать «токен инициатора» с областью действия блокировки в задании в очереди, чтобы задание могло повторно создать экземпляр блокировки с использованием данного токена.
В приведенном ниже примере мы отправим задание в очередь, если блокировка будет успешно получена. Кроме того, мы передадим токен инициатора блокировки заданию в очереди с помощью метода 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();
Обновление блокировок
Если вам нужно продлить срок действия блокировки, которой вы сейчас владеете, вы можете использовать метод refresh. Если количество секунд не передано, будет использована исходная длительность блокировки. Это полезно для долгих операций, когда вы предпочитаете получить короткую блокировку и периодически продлевать ее вместо получения блокировки с очень долгим сроком действия:
$lock = Cache::lock('generate-reports', 60);
if ($lock->get()) {
foreach ($reports as $report) {
$report->generate();
// Продлить блокировку еще на 60 секунд...
$lock->refresh();
}
$lock->release();
}
Ограничение конкурентного выполнения
Функциональность атомарных блокировок Laravel также предоставляет несколько способов ограничить конкурентное выполнение замыканий. Используйте метод withoutOverlapping, когда хотите разрешить только один выполняющийся экземпляр во всей вашей инфраструктуре:
Cache::withoutOverlapping('foo', function () {
// Блокировка получена...
});
По умолчанию блокировка удерживается до завершения выполнения замыкания, а метод ожидает до 10 секунд для получения блокировки. Вы можете настроить эти значения с помощью дополнительных аргументов:
Cache::withoutOverlapping('foo', function () {
// Блокировка получена...
}, lockSeconds: 30, waitSeconds: 5);
Если блокировка не может быть получена в течение указанного времени ожидания, будет выброшено исключение Illuminate\Contracts\Cache\LockTimeoutException.
Если вам нужен контролируемый параллелизм, используйте метод funnel, чтобы задать максимальное количество конкурентных выполнений. Метод funnel работает с любым драйвером кеша, поддерживающим блокировки:
Cache::funnel('foo')
->limit(3)
->releaseAfter(60)
->block(10)
->then(function () {
// Блокировка конкурентного выполнения получена...
}, function () {
// Не удалось получить блокировку конкурентного выполнения...
});
Ключ funnel определяет ограничиваемый ресурс. Метод limit задает максимальное количество конкурентных выполнений. Метод releaseAfter задает защитный тайм-аут в секундах, после которого занятый слот будет автоматически освобожден. Метод block задает количество секунд ожидания доступного слота.
Если вы предпочитаете обрабатывать истечение времени ожидания через исключения вместо передачи замыкания для неудачного сценария, второе замыкание можно опустить. Если блокировка не может быть получена в течение указанного времени ожидания, будет выброшено исключение Illuminate\Cache\Limiters\LimiterTimeoutException:
use Illuminate\Cache\Limiters\LimiterTimeoutException;
try {
Cache::funnel('foo')
->limit(3)
->releaseAfter(60)
->block(10)
->then(function () {
// Блокировка конкурентного выполнения получена...
});
} catch (LimiterTimeoutException $e) {
// Невозможно получить блокировку конкурентного выполнения...
}
Если вы хотите использовать конкретное хранилище кеша для ограничителя конкурентного выполнения, вызовите метод funnel для нужного хранилища:
Cache::store('redis')->funnel('foo')
->limit(3)
->block(10)
->then(function () {
// Блокировка конкурентного выполнения получена через хранилище "redis"...
});
Метод
funnelтребует, чтобы хранилище кеша реализовывало интерфейсIlluminate\Contracts\Cache\LockProvider. Если вы попытаетесь использоватьfunnelс хранилищем кеша, которое не поддерживает блокировки, будет выброшено исключениеBadMethodCallException.
Failover кеша
Драйвер кеша failover предоставляет автоматический failover при работе с кешем. Если основное хранилище кеша в failover-хранилище по какой-либо причине выходит из строя, Laravel автоматически попробует использовать следующее настроенное хранилище из списка. Это особенно полезно для обеспечения высокой доступности в production-средах, где надежность кеша критична.
Чтобы настроить failover cache store, укажите драйвер failover и передайте массив имен хранилищ, которые нужно пробовать по порядку. По умолчанию Laravel включает пример failover-конфигурации в файл конфигурации config/cache.php вашего приложения:
'failover' => [
'driver' => 'failover',
'stores' => [
'database',
'array',
],
],
После настройки хранилища, использующего драйвер failover, вам нужно сделать failover-хранилище хранилищем кеша по умолчанию в файле .env приложения, чтобы задействовать failover-функциональность:
CACHE_STORE=failover
Когда операция cache store завершается ошибкой и активируется failover, Laravel отправит событие Illuminate\Cache\Events\CacheFailedOver, позволяя вам сообщить о сбое cache store или записать его в журнал.
Добавление собственных драйверов кеша
Написание драйвера кеша
Чтобы создать собственный драйвер кеша, сначала нужно реализовать контракт 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. Для примера того, как реализовать каждый из этих методов, взгляните на Illuminate\Cache\MemcachedStore в исходном коде фреймворка Laravel. Как только наша реализация будет завершена, мы можем завершить регистрацию своего драйвера, вызвав метод extend фасада Cache:
Cache::extend('mongo', function (Application $app) {
return Cache::repository(new MongoStore);
});
Если вам интересно, где разместить свой собственный код драйвера кеша, то вы можете создать пространство имен
Extensionsв своем каталогеapp. Однако имейте в виду, что Laravel не имеет жесткой структуры приложения, и вы можете организовать свое приложение в соответствии со своими предпочтениями.
Регистрация драйвера кеша
Чтобы зарегистрировать свой драйвер кеша в Laravel, мы будем использовать метод extend фасада Cache. Поскольку другие поставщики служб могут попытаться прочитать кешированные значения в рамках своего метода boot, мы зарегистрируем свой драйвер в замыкании booting. Используя замыкание booting, мы можем гарантировать, что наш драйвер зарегистрирован непосредственно перед тем, как метод boot вызывается поставщиками служб нашего приложения, и после того, как метод register вызывается для всех поставщиков служб. Мы зарегистрируем наше замыкание booting в методе register класса App\Providers\AppServiceProvider нашего приложения:
<?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
{
/**
* Регистрация любых служб приложения.
*/
public function register(): void
{
$this->app->booting(function () {
Cache::extend('mongo', function (Application $app) {
return Cache::repository(new MongoStore);
});
});
}
/**
* Загрузка любых служб приложения.
*/
public function boot(): void
{
// ...
}
}
Первым аргументом, передаваемым методу extend, является имя драйвера. Оно будет соответствовать вашему параметру driver в файле конфигурации config/cache.php. Второй аргумент – это замыкание, которое должно возвращать экземпляр Illuminate\Cache\Repository. Замыкание будет передано экземпляру $app, который является экземпляром контейнера служб.
После регистрации расширения обновите переменную среды CACHE_STORE или опцию default в файле конфигурации вашего приложения config/cache.php, указав имя вашего расширения.
События
Чтобы выполнить код при каждой операции с кэшем, вы можете прослушивать события, запускаемые кэшем:
| Наименование события |
|---|
Illuminate\Cache\Events\CacheFlushed |
Illuminate\Cache\Events\CacheFlushing |
Illuminate\Cache\Events\CacheFlushFailed |
Illuminate\Cache\Events\CacheLocksFlushed |
Illuminate\Cache\Events\CacheLocksFlushing |
Illuminate\Cache\Events\CacheLocksFlushFailed |
Illuminate\Cache\Events\CacheHit |
Illuminate\Cache\Events\CacheMissed |
Illuminate\Cache\Events\ForgettingKey |
Illuminate\Cache\Events\KeyForgetFailed |
Illuminate\Cache\Events\KeyForgotten |
Illuminate\Cache\Events\KeyWriteFailed |
Illuminate\Cache\Events\KeyWritten |
Illuminate\Cache\Events\RetrievingKey |
Illuminate\Cache\Events\RetrievingManyKeys |
Illuminate\Cache\Events\WritingKey |
Illuminate\Cache\Events\WritingManyKeys |
Чтобы повысить производительность, вы можете отключить события кэширования, установив для параметра конфигурации events значение false для данного хранилища кэша в файле конфигурации config/cache.php вашего приложения:
'database' => [
'driver' => 'database',
// ...
'events' => false,
],