Должен ли я использовать Transient API для хранения HTML-строки или объекта?

18

Давайте предположим, что есть плагин, который отображает 20 связанных постов (для каждого поста) с очень сложным запросом. А затем, используя данные из этого запроса, он создает сложную HTML-разметку. Также следует отметить, что плагин является общедоступным и может быть установлен на любой сервер с любой конфигурацией.

Что-то вроде:

/* complex and large query */
$related_posts = get_posts( ... );

$html_output = '';
foreach($related_posts as $key => $item) {
     /* complex layout rendering logic (but not as slow as the previous query) */   
     $html_output .= ...;
}

Итак, мои вопросы:

  • Какой самый безопасный и правильный способ кеширования таких данных?
  • Должен ли я использовать Transient API для кэширования $related_postsмассива или $html_outputстроки? Если я кеширую $html_ouputстроку, достигнет ли она максимального размера? Должен ли я, возможно, сжать его перед сохранением?
  • Должен ли я использовать Transient API вообще здесь?
Marvin3
источник

Ответы:

18

Должен ли я использовать Transient API вообще здесь?

Нет.

В стандартной версии переходные процессы WordPress хранятся в таблице wp_options и очищаются только при обновлении ядра. Предположим, у вас есть 50 000 сообщений, то есть 50000 дополнительных строк в таблице параметров. Очевидно, что они настроены на автозагрузку = нет, поэтому она не будет занимать всю вашу память, но есть еще одна оговорка.

Поле автозагрузки в таблице параметров не имеет индекса, что означает, что при вызове wp_load_alloptions()выполняется полное сканирование таблицы. Чем больше строк, тем дольше это займет. Чем чаще вы пишете в таблицу параметров, тем менее эффективны внутренние кэши MySQL.

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

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

Еще один важный момент, о котором следует помнить, это то, что переходные процессы WordPress могут быть нестабильными в средах с постоянным кэшированием объектов. Это означает, что если вы храните свои кэшированные данные в течение 24 часов в переходном режиме, нет абсолютно никакой гарантии, что они будут доступны через 23 часа, или 12, или даже 5 минут. Бэкэнд объектного кэша для многих установок - это хранилище значений ключей в памяти, такое как Redis или Memcached, и если недостаточно выделенной памяти для размещения более новых объектов, старые элементы будут удалены. Это огромная победа для мета-хранилища.

Аннулирование тоже может быть умнее, то есть, почему вы аннулируете кеши постов за X часов? Это потому, что какой-то контент изменился? Новый пост был добавлен? Новый тег был назначен? В зависимости от вашего «сложного и большого запроса» вы можете выбрать ТОЛЬКО аннулирование, если произошло что-то, что изменит результаты вашего запроса.

Должен ли я использовать Transient API для кэширования массива $ related_posts или строки $ html_output? Если я кеширую строку $ html_ouput, достигнет ли она какого-нибудь максимального размера? Должен ли я, возможно, сжать его перед сохранением?

Это во многом зависит от размера вашей строки, поскольку именно эти данные будут передаваться между PHP, MySQL и т. Д. Вам нужно будет очень постараться, чтобы достичь пределов MySQL, но, например, Memcached по умолчанию для каждого объекта: только 1 мб.

Сколько времени на самом деле занимает ваша «логика рендеринга сложной компоновки»? Запустите его через профилировщик, чтобы узнать. Скорее всего, это очень быстро никогда не станет узким местом.

Если это так, я бы предложил кэшировать идентификаторы постов. Не объекты WP_Post, потому что они будут содержать полное содержимое сообщения, а только массив идентификаторов сообщений. Затем просто используйте WP_Queryс, post__inчто приведет к очень быстрому запросу MySQL по первичному ключу.

Тем не менее, если данные, необходимые для каждого элемента, довольно просты, например, заголовок, URL-адрес миниатюры и постоянная ссылка, то вы можете хранить только эти три, без дополнительных затрат на обходные пути в MySQL и без дополнительных затрат на кэширование очень длинного HTML. строки.

Вау, это много слов, надеюсь, это поможет.

КОВШЕНИН
источник
12

Не весь код WP является открытым

Если вы собираетесь выпустить что-то публичное, то все сказанное Ковшениным совершенно справедливо.

Все по-другому, если вы собираетесь написать личный код для себя или своей компании.

Кэш внешних объектов - это большое преимущество, в любом случае

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

Все сказанное в ответе Ковшенина о переходных процессах и MySQL очень верно, и, учитывая, что сам WP и несколько плагинов используют кэш объектов ... тогда улучшение производительности, которое вы получили, абсолютно стоит (небольших) усилий по настройке. современная система кэширования, такая как Redis или Memcached.

Кэшированные значения могут отсутствовать: это нормально

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

Кеш - это не хранилище, кеш - это кеш.

Используйте кэш выборочно

Смотрите этот пример:

function my_get_some_value($key) {
   // by default no cache when debug and if no external object_cache
   $defUse = ! (defined('WP_DEBUG') && WP_DEBUG) && wp_using_ext_object_cache();
   // make the usage of cache filterable
   $useCache = apply_filters('my_use_cache', $defUse);
   // return cached value if any
   if ($useCache && ($cached = get_transient($key))) {
     return $cached;
   }
   // no cached value, make sure your code works with no cache
   $value = my_get_some_value_in_some_expensive_way();
   // set cache, if allowed
   $useCache and set_transient($key, $value, HOUR_IN_SECONDS);

   return $value;
}

Использование подобного кода в вашем частном месте, производительность сайта может улучшить много , особенно если у вас есть много пользователей.

Обратите внимание, что:

  • По умолчанию кеш не используется при включенной отладке, так что, надеюсь, в вашей среде разработки. Поверьте, кеш может сделать отладку адом
  • По умолчанию кеш также не используется, если WP не настроен на использование внешнего кеша объектов. Это означает, что все проблемы, связанные с MySQL, не существуют, потому что вы не используете переходные процессы, когда они используют MySQL. Вероятно, более простой альтернативой было бы использование wp_cache_*функций , поэтому, если внешний кэш не настроен, тогда кэш создается в памяти, а база данных никогда не задействуется.
  • Использование кэша фильтруется, чтобы справиться с некоторыми крайними случаями, с которыми вы можете столкнуться

Нет веб-шкалы, если нет кэша

Вы не должны пытаться решить проблемы со скоростью кеша. Если у вас есть проблемы со скоростью, вам следует пересмотреть свой код.

Но для масштабирования веб-сайта на веб-уровне кэш-память довольно необходима .

И во многих случаях (но не всегда) фрагментно-зависимый кеширование является гораздо более гибким и подходящим, чем агрессивное кеширование полной страницы.

Ваши вопросы:

Должен ли я использовать Transient API вообще здесь?

Это зависит .

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

Если вы понимаете, кеш будет хорошей идеей ..

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

... и это частный код: очень вероятно, да . Но даже для частного кода выборочное кеширование все еще хорошо, например, для отладки.

В любом случае, помните, что wp_cache_*функции могут предоставить вам доступ к кешу без риска загрязнения базы данных.

Должен ли я использовать Transient API для кэширования массива $ related_posts или строки $ html_output?

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

Финальные заметки

Transient API - это, вероятно, одна из лучших вещей WordPress. Благодаря плагинам, которые вы можете найти для любого типа систем кэширования, он превращается в глупый простой API для большого количества программ, которые могут работать под капотом.

За пределами WordPress очень сложно найти такую ​​абстракцию, которая работает «из коробки» с кучей различных систем кеширования и позволяет переключаться с одной системы на другую без особых усилий.

Вы редко слышите, как я говорю, что WordPress лучше других современных вещей, но переходный API - одна из немногих вещей, которые мне не хватает, когда я не работаю с WordPress.

Конечно, кеш труден, не решает проблем с кодом и не является серебряной пулей, но это то, что вам нужно для создания сайта с высоким трафиком, который работает.

Идея WordPress использовать недостаточно оптимизированную таблицу MySQL для кеширования довольно безумна, но не лучше держаться подальше от кеша только потому, что WordPress по умолчанию это делает.

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

gmazzap
источник
2

В предыдущих ответах уже подчеркивалось обязательное « зависит », с которым я полностью согласен.

Я хотел бы добавить рекомендацию, основанную на том, как я « предполагаю », что это лучше всего сделать в сценарии, который вы описываете выше.

В этом случае я бы не использовал переходные процессы , а, скорее, Post Meta из-за одного преимущества последнего: Control .

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

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

Имейте в виду, что все кэширование - это компромисс! Вот почему обычный ответ: «Это зависит». и почему нет "святого кэширующего грааля".

Ален Шлессер
источник