Как работает кэширование в WordPress

Дата публикации:Февраль 25, 2018

Кэширование порой подается как «святой Грааль» для всех проблем с производительностью. Неудивительно, что пользователей нередко ставит в тупик утверждение «хватит использовать кэширование» в моих презентациях, на семинарах и воркшопах. Некоторые в сообществе WordPress стали называть меня «тем парнем, который ненавидит кэширование». Пришла пора разъяснить, что я в действительности думаю по этому вопросу. Когда и в каких ситуациях кэширование действительно оправдывает себя? Как отказаться от него? Какие альтернативные решения существуют?

Когда нужно использовать кэширование страниц?

Давайте начнем с самого крупного – кэширования страниц. Вот как оно работает на практике:

  1. Посетитель A заходит на abc.com/page. Этой страницы нет в кэше, а потому запускается PHP и страница генерируется из базы данных. Перед тем, как страница будет передана посетителю, она также сохранятся в кэш сроком действия в 10 минут.
  2. Посетитель B заходит на abc.com/page через 2 минуты после посетителя A и потому получает ту же самую страницу, но на этот раз непосредственно из кэша. Страницы, передаваемые A и B, полностью идентичны.
  3. Посетитель C заходит на abc.com/page через 15 минут после посетителя A, и, поскольку срок действия кэшированной версии страницы истек, запрос приводит к выполнению PHP, и страница повторно генерируется, как и в случае с посетителем A.

Если каждый посетитель, просматривающий страницу в установленный промежуток времени, укладывается в срок жизни кэша, то страница выдается очень быстро. Кэширование способно повысить производительность и, что более важно, масштабируемость. Это может выглядеть привлекательно, но кэширование страниц имеет и свои серьезные недостатки.

  1. Если вы хотите поставлять динамический контент, персонализированный, различный для каждого пользователя – это реализуется с помощью javascript (ajax), который запускается после того, как HTML-документ поставляется посетителю. Это классно, но для этого требуется дополнительный запрос к серверу. Если вы используете кэширование, вы столкнетесь с проблемой, связанной с вашими динамическими Ajax запросами.
  2. Если что-то работает быстро у вас, это не значит, что то же самое будет быстро работать и у других. Веб-сайты не имеют единой точки входа, и посетители переходят к вам на ресурс разными путями. Это особенно актуально для WooCommerce, когда посетители используют Google и переходят на продуктовые страницы. Кто-то переходит через Google Shopping, Яндекс Маркет и т.д. Чтобы справиться с этой проблемой, некоторые вебмастера пытаются сформировать базовый кэш страниц для роботов, которые обходят сайт, чтобы убедиться, что все страницы были заранее кэшированы. Но на практике это не всегда срабатывает. Такой кэш уязвим, его сложно настроить и сконфигурировать, тяжело поддерживать, все это отнимает очень много времени – да и не нужно это в целом.
  3. Вы теряете контроль над реальной производительностью своего сайта, не знаете, как работает код (или работает не так, как должен был). Если вы используете страничное кэширование, вы лишаетесь понимания того, насколько быстр ваш сайт, насколько хорош ваш код. Опыт показывает, что недостаточная забота о производительности сайта приводит к тому, что сайты падают во время Черной пятницы или в процессе проведения крупных рекламных кампаний.

Что по поводу плагинов кэширования, таких как W3 Total Cache?

Плагины WordPress, такие как W3 Total Cache, работают по аналогии с любым другим кэшированием страниц. Они сохраняют версию заранее сгенерированной страницы в файловую систему или память и выдают ее пользователям, пока ее срок действия не истечет. W3 Total Cache используется на 1 млн сайтов, но это не означает, что это хорошая идея. Особенно если вы используете быстрый хостинг.

W3 Total Cache – очень крупный плагин, и для большинства сайтов он добавляет много лишнего кода. Больше кода – больше проблем. Если вам действительно нужно страничное кэширование, его не нужно выполнять на PHP уровне вашего приложения, поскольку PHP сам по себе достаточно медленный. Кэширование страниц должно быть выполнено максимально близко к пользователям на сервере (nginx в нашем случае).

W3 Total Cache показывает, как можно загружать страницы менее чем за 2 с, используя тему twentysixteen.  Подобный тест на наших серверах привел к тому, что страницы доставлялись менее чем за 100 мс, причем без использования кэширования.

В каких ситуациях требуется кэширование страниц и почему?

Кэширование страниц было придумано для масштабирования сайтов с огромным трафиком, чтобы легче обрабатывать всплески трафика. Придумано оно было в те времена, когда пользователи обращались к веб-ресурсам в основном для чтения новостных статей. Страницы новостных сайтов по большей части статичны и обновляются лишь иногда. В таком случае кэширование страниц подходит, однако современные сайты больше напоминают приложения.

Современные сайты более сложны, динамичны и более персонализированы. Их код довольно запутан, и добавлять еще более сложные механизмы (читай: методы кэширования) поверх этого сложного кода – не самая удачная идея. На практике вы добавляете еще один уровень технологий, который вводит новые отдельные точки отказа, требующие специального обслуживания, обновления и операций. В итоге баги сложнее обнаружить и решить, а общая разработка становится заметно дороже. Если вы формируете производительность вокруг кэширования страниц, то я гарантирую вам, что все перестанет работать, если произойдут какие-либо перебои с кэшированием.

Потому ответ на вопрос заключается в том, чтобы писать хороший код и запросы, и учитывать, что решение должно иметь возможность масштабирования. Использовать кэширование страниц можно для обработки внезапных всплесков трафика, как это делали (и сейчас делают) новостные ресурсы.

В обычное время с обычным трафиком вы должны быть в состоянии отключить кэширование страниц, не переживая об этом. Если вы все сделали правильно, то вы сможете отключить кэширование и в те дни, когда трафик достаточно высокий – причем ваш сайт не рухнет.

У нас большая часть магазинов работает без кэширования страниц – даже в те дни, когда трафик очень высок, как, к примеру, в Черную пятницу.

Объектное кэширование WordPress – вы используете его, но не знаете об этом

Многие люди не знают, что объектное кэширование WordPress используется практически на всех WordPress сайтах. Да, объектный кэш эффективен, даже если вы не используете сторонний кэш объектов, как MemCached или REDIS.

Как работает объектный кэш в WordPress?

  1. Вы делаете запрос, к примеру, для значений postmeta путем использования get_post_meta().
  2. WordPress выполняет запрос и получает результаты из базы данных, и автоматически сохраняет результат в объектный кэш (память).
  3. Вы получаете результат и используете его где-то в вашем коде.
  4. Позже в вашем коде вы делаете еще один запрос get_post_meta для тех же самых данных.
  5. WordPress уже имеет эти данные в объектном кэше, а потому возвращает результат напрямую из кэша без повторного запроса к базе данных.
  6. Страница поставляется посетителю, а объектный кэш чистится (освобождается память).

Не все функции в WordPress сохраняют свои результаты в кэш объектов, но get_post_meta делает это. Это связано с тем, что _postmeta таблица в базе данных может разрастись очень быстро, и запросы могут стать достаточно ресурсоемкими.

Вы можете добавлять результаты в объектный кэш самостоятельно, чтобы ускорить повторное использование тех же самых данных в будущем. Если вы пишете свои собственные запросы с помощью, скажем, WP_Query, вы можете сохранить результаты в объектный кэш. Важно помнить, что, как и в случае с любым другим кэшированием, вы не должны полагаться только на него. Убедитесь, что ваш код не исходит из предположения, что результаты хранятся в кэше объектов.

Вы можете проверить производительность кэша объектов и количество запросов к базе данных, установив такой плагин, как Query Monitor. В моих тестах со стандартным WooCommerce нормальный процент попадания в объектный кэш составил 95-98%.

Как использовать объектный кэш WordPress для ваших собственных запросов

$result = wp_cache_get( 'some_unique_name' ); 
if ( false === $result ) { 
   $result = $wpdb->get_results( $query );
   wp_cache_set( 'some_unique_name', $result );
}
// Do something with $result;

Что делает данный код? Здесь мы пытаемся сначала получить $result, а затем проверяем, есть ли что-нибудь в этой переменной. wp_cache_get() вернет false, если переменная не существует. Если данных нет, мы запускаем запрос для наших данных, после чего сохраняем результат с помощью wp_cache_set(), чтобы данные были доступны для наших следующих запросов.

Что по поводу сторонних объектных кэшей, таких как MemCached и REDIS?

Внешний объектный кэш позволяет реализовать то, что часто именуется как «постоянный объектный кэш». Это кэш объектов, который не очищается во время просмотров страниц, поэтому он сохраняет данные в процессе просмотров разных страниц. Умная идея, не так ли? Но, как и всегда с кэшированием, не все так просто.

  1. Потенциальный прирост производительности от использования постоянного кэша связан с переходами, которые обходят объектный кэш. Учитывая, что процент попадания в стандартный объектный кэш составляет где-то 95-98%, потенциальный прирост производительности может быть 2-5% от запроса. В дополнение ко всему, внешний объектный кэш добавляет дополнительную задержку, поскольку это стороннее приложение – а потому оно замедлит те 95-98%, которые передавались напрямую в PHP ранее. Добавленная задержка + прирост производительности от внешнего объектного кэша зачастую уходит в минус для интернет-магазинов.
  2. Даже если вы используете внешний объектный кэш, вы не можете убедиться в том, что информация существует в нем, когда пишете код.
  3. Если вы зависите от внешнего объектного кэша для ускорения загрузки страниц, это означает, что ваш код является плохим, ваши запросы к базе данных достаточно весомы либо их слишком много. Реальная проблема заключается в вашем коде, а не в том, насколько быстро база данных отвечает на запросы. По этой причине вы не должны полагаться на «костыли» в виде MemCached или Redis.
  4. Если вы используете быструю базу данных, которая оптимизирована, и правильно используете индексы, вам не нужен внешний объектный кэш.

Если вам не нужен внешний объектный кэш, то его использование может только навредить

Это относится ко всем технологиям, которые вы включаете в свой стек, но которые вам не требуются. В итоге вы можете зависеть от них, хотя они вам даже не нужны. Если вы зависите от таких технологий, то вы увеличиваете вероятность того, что что-то может пойти не так. Кроме того, каждая новая технология в стеке требует установки, настройки, обслуживания, обновлений безопасности – и вводит еще одну точку отказа.

Transients – хорошая альтернатива, но они тоже могут сломать сайт

Transients (временные данные) используются и самой системой WordPress, и разными плагинами. Их концепция достаточно проста. Вы делаете запрос и сохраняет его результат или часть его в базе данных для последующего использования. В отличие от объектного кэша, вам не требуются дополнительные технологии, чтобы сделать эти данные постоянными в процессе просмотра страниц, поскольку они хранятся в базе данных. Transients могут иметь время истечения, а могут и не иметь – это ваш выбор.

Я лично не поддерживаю фанатичное использование transients, и вот почему:

  1. Transients сохраняются в таблице _options WordPress. Эта таблица уже достаточно активно используется, и излишнее ее раздувание может вызвать проблемы с блокировкой (очередью запросов).
  2. Чрезмерное использование transients приводит к разрастанию таблицы _options. Каждый отдельный просмотр страниц зависит от этой таблицы, и крупная таблица опций может снизить производительность сайта.
  3. Transients, которые не истекли, запрашиваются во время каждой загрузки страницы через wp_load_alloptions(). Это снижает производительность всех просмотров страниц.

При этом transients могут давать и плюсы в плане производительности, если их корректно использовать. Если вы запрашиваете данные, которые используются и меняются редко, вы можете сохранить результат в transients. Для WordPress намного проще получить значение из ключа X таблице опций, чем выполнять выборки по всем остальным таблицам.  Если вы используете transients, убедитесь в том, что таблица _options не разрастается слишком сильно, выполняйте очистку transients, которые больше не используются или истекли. Никогда не используйте transients для данных, требующих частых обновлений, это негативно скажется на производительности.

Кэширование фрагментов – хороший вариант, если используется грамотно

Кэш фрагментов – такой тип кэширования, когда вы сохраняете элемент, часть страниц или что-то еще, что является ресурсоемким при генерации и/и используется часто.

Кэширование фрагментов означает сохранение результата (HTML вывод), чтобы он мог доставляться гораздо быстрее. Идея проста и великолепна. Вы можете выбрать, какие элементы кэшировать, и вам не нужно кэшировать полный вывод, как в случае с кэшированием страниц.

В WordPress процесс кэширования фрагментов эквивалентен кэшированию объектов, поскольку нет никаких ограничений на то, какие данные вы можете кэшировать. Применяются те же самые принципы – не исходите из предположения, что что-то было кэшировано, пишите полноценный код с проверками.

Многие реализуют кэширование фрагментов в памяти. Но для этого потребуется внешний объектный кэш, чтобы элементы были доступны в процессе просмотра страниц. Я рекомендую аккуратно использовать кэширование фрагментов – советую хранить данные в transients вместо объектного кэша. В итоге вы получите те же результаты в плане производительности без добавления дополнительных технологий в ваш стек.

Как сохранить transients

$output = get_transient('some_unique_key');
if( $output === false ){
$output = 'Some data';
set_transient('some_unique_key', $output, 3600);
}
// Do something with $output

Здесь мы получаем $output из transient и проверяем, существует ли $output. Если get_transient() выводит false, то в таком случае мы генерируем данные и сохраняем их в transient для последующего использования.

Какую методику кэширования я должен использовать?

Используйте кэширование страниц для масштабирования сайта. Оно было создано для этого, а не для повышения производительности. Не зависьте от него. Вы должны иметь возможность отключения кэширования без существенного падения производительности.

Используйте объектный кэш там, где это возможно, особенно для WooCommerce, однако избегайте внешних кэшей, поскольку они могут приводить к новым проблемам. Вместо них лучше всего перейти на быстрый хостинг с высокопроизводительными базами данных.

Вы должны использовать transients для частых запросов, которые мало меняются. Обязательно установите подходящую дату истечения, основанную на том, как часто данные должны обновляться. Также убедитесь в том, что истекшие transients удаляются. Используйте кэширование фрагментов в transients для элементов, которые потребляют много ресурсов и которые используются довольно часто.

Источник: https://servebolt.com

Поделиться

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.