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

Дата оновлення перекладу 2022-11-11

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

Пули кеша - це логічні сховища кешованих обʼєктів. Вони проводять всі загальні операції на обʼєктах, на кшталт їх збереження або пошуку. Пули кешів не залежать від самої реалізації кеша. Відповідно, додатки можуть продовжувати використовувати один і той же пул кеша, навіть якшо основний механізм кеша змінюється з кеша, заснованого на файловій системі, на кеш, заснований на 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) {
    $item->expiresAfter(3600);

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

    return $computedValue;
});

echo $value; // 'foobar'

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

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

Раннє закінчення строку дії можна виявити всередині зворотного виклику, викликавши метод 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 , 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