Пули кешу та підтримувані адаптери

Дата оновлення перекладу 2024-04-30

Пули кешу та підтримувані адаптери

Пули кешу - це логічні сховища кешованих обʼєктів. Вони проводять всі загальні операції на обʼєктах, на кшталт їх збереження або пошуку. Пули кешів не залежать від самої реалізації кешу. Відповідно, додатки можуть продовжувати використовувати один і той же пул кешу, навіть якшо основний механізм кешу змінюється з кешу, заснованого на файловій системі, на кеш, заснований на Redis або БД.

Використання контрактів кешу

CacheInterface дозволяє вилучення, зберігання та видалення обʼєктів кешу, використовуючи лише два методи та зворотний виклик:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Contracts\Cache\ItemInterface;

$cache = new FilesystemAdapter();

// Викликане буде виконано лише за умови промаху кешу.
$value = $cache->get('my_cache_key', function (ItemInterface $item): string {
    $item->expiresAfter(3600);

    // ... зробити якийсь HTTP-запит або складні обчислення
    $computedValue = 'foobar';

    return $computedValue;
});

echo $value; // 'foobar'

// ... і щоб видалити ключ кешу
$cache->delete('my_cache_key');

Одразу після установки, використання цього інтерфейсу надає стихійний захист через блокування та раннє закінчення строку дії. Ранні закінчення строку дії можна контролювати через третій "бета" аргумент методу get(). Див. статтю Компонент Cache, щоб дізнатися більше.

Раннє закінчення строку дії можна виявити всередині зворотного виклику, викликавши метод isHit(): якщо він повертає true, це означає, що ми наразі перераховуємо значення до його строку закінчення дії.

Для просунутих випадків використання, зворотний виклик може приймати другий аргумент bool &$save, переданий посиланням. Встановивши $save як false всередині зворотного виклику, ви можете проінструктувати пул кешу, що повернене значення не повинно зберігатися у бекенді.

Пошук обʼєктів кешу

Пули кешу визначають три методи пошуку обʼєктів кешу. Найрозповсюдженішим методом є getItem($key), який повертає ідентифікатор обʼєкта кешу за заданим ключем:

1
2
3
4
use Symfony\Component\Cache\Adapter\FilesystemAdapter;

$cache = new FilesystemAdapter('app.cache');
$latestNews = $cache->getItem('latest_news');

Якщо для заданого ключа не визначено жодного обʼєкта, метод не повертає значення null, а поветає порожній обʼєкт, що реалізує клас CacheItem.

Якщо вам потрібно вилучити декілька обʼєктів кешу одночасно, то краще використайте метод getItems(array($key1, $key2, ...)):

1
2
// ...
$stocks = $cache->getItems(array('AAPL', 'FB', 'GOOGL', 'MSFT'));

Знову ж, якщо жоден з ключів не представляє валідний обʼєкт кешу, ви не отримаєте значення null, а отримаєте порожній обʼєкт CacheItem.

Останній метод, повʼязаний з вилученням обʼєктів кешу, є hasItem($key), який повертає true, якщо існує обʼєкт кешу, ідентифікований заданим ключем:

1
2
// ...
$hasBadges = $cache->hasItem('user_'.$userId.'_badges');

Збереження обʼєктів кешу

Найрозповсюдженішим методом для збереження обʼєктів кешу є Psr\\Cache\\CacheItemPoolInterface::save, який зберігає обʼєкт у кеші негайно (повертає true, якщо обʼєкт було збережно, або false, якщо сталася якась помилка):

1
2
3
4
// ...
$userFriends = $cache->getItem('user_'.$userId.'_friends');
$userFriends->set($user->getFriends());
$isSaved = $cache->save($userFriends);

Іноді вам може захотітися не зберігати обʼєкти негайно, щоб підвисити продуктивність вашого додатку. У таких випадках використайте метод Psr\\Cache\\CacheItemPoolInterface::saveDeferred, щоб відмітити обʼєкти кешу, як "готові до збереження", а потім викличте метод Psr\\ache\\CacheItemPoolInterface::commit, коли ви будете готові зберегти їх всі:

1
2
3
4
5
6
7
8
// ...
$isQueued = $cache->saveDeferred($userFriends);
// ...
$isQueued = $cache->saveDeferred($userPreferences);
// ...
$isQueued = $cache->saveDeferred($userRecentProducts);
// ...
$isSaved = $cache->commit();

Метод saveDeferred() повертає true, коли обʼєкт кешу був успішно доданий у "чергу збереження", і false в інших випадках. Метод commit() повертає true, коли всі обʼєкти, що очікують, були успішно збережені, і false в інших випадках.

Видалення обʼєктів кешу

Пули кешу включають методи для видалення обʼєктів кешу, деяких з них, або всіх.
Найрозповсюдженішим є Psr\\Cache\\CacheItemPoolInterface::deleteItem, який видаляє обʼєкт кешу, що визначається заданим ключем (повертає true, коли обʼєкт був успішно видалений або не існує, і false в інших випадках):

1
2
// ...
$isDeleted = $cache->deleteItem('user_'.$userId);

Використайте метод Psr\\Cache\\CacheItemPoolInterface::deleteItems, щоб видалити декілька обʼєктів кешу одночасно (повертає true лише якщо всі обʼєкти були видалені, навіть якщо один або декілька з них не існують):

1
2
// ...
$areDeleted = $cache->deleteItems(array('category1', 'category2'));

Нарешті, щоб видалити всі обʼєкти кешу, що зберігаються у пулі, використайте метод Psr\\Cache\\CacheItemPoolInterface::clear (який повертає true, коли всі обʼєкти були успішно видалені):

1
2
// ...
$cacheIsEmpty = $cache->clear();

Tip

Якщо компонент кешу використовується всередині додатку Symfony, ви можете видалити обʼєкти з пулів кешу, використовуючи наступні команди (які знаходяться в рамках пакету framework):

Для того, щоб видалити один конкретний обʼєкт з заданого пулу:

1
2
3
4
$ php bin/console cache:pool:delete <cache-pool-name> <cache-key-name>

# видаляє обʼєкт "cache_key" з пулу "cache.app"
$ php bin/console cache:pool:delete cache.app cache_key

Ви також можете видалити всі обʼєкти з заданого пулу(ів):

1
2
3
4
5
6
7
$ php bin/console cache:pool:clear <cache-pool-name>

# очищує пул "cache.app"
$ php bin/console cache:pool:clear cache.app

# очищує пули "cache.validation" і "cache.app"
$ php bin/console cache:pool:clear cache.validation cache.app

Відсікання обʼєктів кешу

Деякі пули кешу не включають в себе автоматизований механізм для відсікання прострочених обʼєктів кешу. Наприклад, кеш FilesystemAdapter не видаляє прострочені обʼєкти кешу, поки обʼєкт не буде чітко запитано і визначено, як прострочений, наприклад, через виклик до Psr\\Cache\\CacheItemPoolInterface::getItem. При певному навантаженні, це може призвести до зберігання застарілих записів кешу після строку закінчення їх дії, що, у свою чергу, призведе до відчутного споживання марно витраченого простору на диску або памʼяті у звʼязку з надмірними простроченими обʼєктами кешу.

Цей недолік було вирішено шляхом введення PruneableInterface, який визначає абстрактний метод prune(). ChainAdapter, DoctrineDbalAdapter, and FilesystemAdapter, PdoAdapter та PhpFilesAdapter - всі реалізують цей новий інтерфейс, дозволяючи ручне видалення застарілих обʼєктів кешу:

1
2
3
4
5
use Symfony\Component\Cache\Adapter\FilesystemAdapter;

$cache = new FilesystemAdapter('app.cache');
// ... провести якісь операції set і get
$cache->prune();

Релізація ChainAdapter не містить напряму ніякої логічки відсікання. Замість цього, при виклику методу ланцюжка адаптерів prune(), виклик делегується усім сумісним з ним адаптерам кешу (а ті, як не реалізують PruneableInterface, тихо ігноруються):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Cache\Adapter\ChainAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\PdoAdapter;
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;

$cache = new ChainAdapter(array(
    new ApcuAdapter(),       // НЕ реалізує PruneableInterface
    new FilesystemAdapter(), // РЕАЛІЗУЄ PruneableInterface
    new PdoAdapter(),        // РЕАЛІЗУЄ PruneableInterface
    new PhpFilesAdapter(),   // РЕАЛІЗУЄ PruneableInterface
    // ...
));

// відсікання проксує виклик до PdoAdapter, FilesystemAdapter та PhpFilesAdapter,
// тихо пропустивши ApcuAdapter
$cache->prune();

Tip

Якщо компонент кешу використовується всередині додатку Symfony, то ви можете відсікти всі обʼєкти з усіх пулів, використовуючи наступну команду (яка знаходиться у пакеті framework):

1
$ php bin/console cache:pool:prune