Система кеша в Drupal имеет ряд различных компонентов со временем, контекстами и тегами, используемыми для определения кеша.
Хотя все эти механизмы действительно полезны, вы также можете вводить данные непосредственно в систему кэширования. Это полезно, если у вас есть функция, выполнение которой занимает много времени. Результат функции может храниться в системе кэширования Drupal точно так же, как и другие данные кэша.
Например, допустим, вы извлекаете данные из медленного API. Если данные не сильно меняются, может быть лучше добавить кеш к запросу, чтобы вместо перехода к медленному API использовались быстрые системы кеширования.
Чтобы получить экземпляр системы кэширования, вы можете использовать метод \Drupal::cache(), который вернет экземпляр объекта типа CacheBackendInterface. По умолчанию предполагается, что вы хотите использовать корзину кеша «по умолчанию», которая по сути является таблицей cache_default (при условии, что вы используете базу данных для хранения кеша).
Когда у вас есть объект кеша, вы можете использовать несколько важных методов.
Методы кэширования
Первый метод, о котором следует поговорить, — это метод set(), который используется для записи некоторого кеша в систему кеша. Он принимает несколько параметров и вызывается так.
\Drupal::cache()->set($cacheId, $data, Cache::PERMANENT, $cacheTags);
Пройдемся немного по параметрам.
- $cacheId — это строка, которая используется для идентификации данных кэша в вашей системе кэширования. Это будет использоваться позже для обратного чтения данных кэша.
- $data — второй параметр — это просто данные, которые вы хотите кэшировать. Это может быть простое значение или более сложный массив. Данные автоматически сериализуются, поэтому, если данные сериализуемы, данные можно сохранить.
- Cache::PERMANENT — третий параметр — это период времени, в течение которого должен храниться кеш. Вы можете либо добавить то, что я добавил здесь (константа Cache::PERMANENT, которая будет хранить кэш навсегда), либо вы можете добавить временную метку. Временная метка сообщает Drupal время, когда кеш следует считать просроченным. Элементы кэша с истекшим сроком действия периодически очищаются системами сбора мусора Drupal. Это необязательный аргумент, и Cache::PERMANENT предполагается, если он не указан.
- $cacheTags — при желании вы можете передать массив тегов кеша. Они используются Drupal для аннулирования этого элемента кеша при изменении других вещей на сайте. Например, вы можете передать тег «узел: 1», чтобы при изменении узла объекта 1 этот элемент кеша становился недействительным, чтобы можно было создавать новые кеши.
И наоборот, метод get() используется для получения некоторых данных из системы кэширования. Этот метод принимает идентификатор кеша, который вы хотите получить.
$output = \Drupal::cache()->get($cacheId);
Этот метод либо вернет «false», если кеш не найден, либо объект stdClass, который содержит данные кеша, сохраненные в параметре «data».
Метод get() обычно используется в операторе if, так что если результат метода get() затем передается вверх по течению, а не продолжает выполнение функции.
if ($cache = \Drupal::cache()->get($cacheId)) {
return $cache->data;
}
Вы также можете передать второй параметр, чтобы заставить метод get() разрешить возврат недействительных элементов кэша. Это все еще используется таким же образом.
if ($cache = \Drupal::cache()->get($cacheId, TRUE)) {
return $cache->data;
}
Это полезно в определенных ситуациях, когда регенерация кеша занимает много времени, и вам нужно быть уверенным, что что-то извлечено из кеша, даже если оно устарело. Затем вы можете повторно сгенерировать кеш с помощью других процессов.
Собираем вещи вместе
Эти методы обычно объединяются следующим образом. Если метод get() возвращает ложное значение, мы продолжаем генерировать данные кэша и сохранять их в кэше с помощью метода set().
$cacheId = 'my_cache';
if ($cache = \Drupal::cache()->get($cacheId)) {
return $cache->data;
}
$data = ['некоторые данные для кэширования'];
\Drupal::cache()->set($cacheId, $data, Cache::PERMANENT);
return $data;
Вы можете добавить этот шаблон кода везде, где вам нужно активно хранить данные в системе кэширования Drupal.
Пример добавления Cache API в медленный блок
В качестве примера того, как эту систему можно использовать для решения медленного кода, я создал простой блок Drupal.
Следующий блок отключает кеш страницы, чтобы он мог регенерировать некоторый вывод на страницу при каждой загрузке страницы. Это вычисляет количество узлов на сайте, используя очень неэффективный метод, а затем возвращает это значение в массив рендеринга для вывода на печать. Это может показаться произвольным способом замедлить работу сайта, но несколько лет назад я видел сайт, содержащий аналогичный код, из-за которого сайт действительно работал очень медленно. Рассматриваемый код может быть чем угодно, что замедляет процесс рендеринга, включая поиск API, медленные запросы к базе данных или просто процессы, выполнение которых занимает много времени.
<?php
namespace Drupal\mymodule\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Cache\Cache;
class CachedBlock extends BlockBase implements ContainerFactoryPluginInterface {
protected $entityTypeManager;
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) { parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager'),
);
}
public function build() {
$build = [];
\Drupal::service('page_cache_kill_switch')->trigger(); $build['output'] = [ 'markup' => '<p>' . $this->expensiveMethod() . '</p>',
];
return $build;
}
public function expensiveMethod() {
$count = 0;
$nodes = $this->entityTypeManager->getStorage('node')->loadMultiple();
foreach ($nodes as $node) {
$count++;
}
$output = $this->t('There are :count nodes on this site.', [':count' => $count]);
return $output;
}
public function getCacheMaxAge() {
return 0;
}
}
Добавляя этот блок на главную страницу, мы создаем ситуацию, когда чем больше страниц на сайте, тем медленнее будет загружаться страница. Анализ производительности легко покажет, что для запуска метода() требуется некоторое время.
Мы можем начать улучшать код, добавив шаблон кеша, чтобы мы сохраняли вывод вычислений в кеш. При этом, если в кеше есть что-то, оно будет возвращено вместо повторного вычисления.
public function expensiveMethod() {
$cacheId = 'mymodule:cachedblock';
if ($cache = \Drupal::cache()->get($cacheId)) {
return $cache->data;
}
$count = 0;
$nodes = $this->entityTypeManager->getStorage('node')->loadMultiple();
foreach ($nodes as $node) {
$count++;
}
$data = $this->t('There are :count nodes on this site.', [':count' => $count]);
\Drupal::cache()->set($cacheId, $data, time() + 86400);
return $data;
}
Кэш здесь настроен на 86400 секунд (т.е. 1 день) в будущем, что означает, что установленный нами кеш будет регенерироваться каждый день и показывать последний подсчет количества узлов.
Мы можем улучшить это, добавив теги кеша в метод set(). Поскольку мы смотрим на узлы, мы можем использовать отдельный тег кеша «node:n» для каждого из просматриваемых узлов и тег кеша «node_list» для списка узлов в целом. Документация Drupal содержит информацию о том, какие теги кэша доступны.
Создав массив тегов кеша, мы передаем его методу set().
public function expensiveMethod() {
$cacheId = 'mymodule:cachedblock';
if ($cache = \Drupal::cache()->get($cacheId)) {
return $cache->data;
}
$cacheTags = [];
$count = 0;
$nodes = $this->entityTypeManager->getStorage('node')->loadMultiple();
foreach ($nodes as $node) {
$count++;
$cacheTags[] = 'node:' . $node->id();
}
$cacheTags[] = 'node_list';
$data = $this->t('There are :count nodes on this site.', [':count' => $count]);
\Drupal::cache()->set($cacheId, $data, time() + 86400, $cacheTags);
return $data;
}
Устанавливая теги кеша, мы сообщаем Drupal, какую информацию содержит этот кеш. Это означает, что если мы добавим или удалим один из узлов, кеш станет недействительным.
Этот метод является хорошим способом решения проблем с неэффективным кодом и дает немедленный прирост производительности в ситуациях, когда кеш обходится и выполняется медленный код. При таком простом изменении хотя бы один пользователь в день увидит медленный отклик страницы, но общее состояние страницы будет гораздо более производительным. Это, по крайней мере, позволяет вам работать над улучшением основной проблемы с производительностью, но при этом позволяет сайту функционировать.