Как работает кеширование объектов?

21

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

По умолчанию оба хранятся в базе данных. Но я слышал некоторые упоминания о том, что memcache будет хранить их в другом месте, а APC сделает что-то еще полностью. Где именно эти данные будут сохраняться в обоих случаях?

EAMann
источник
2
Статья, о которой упоминает @toscho, теперь доступна на archive.org: изучение API кеша WordPress
здесь

Ответы:

34

WordPress по умолчанию выполняет форму «Кеширования объектов», но его время жизни составляет всего одну загрузку страницы.

Параметры на самом деле действительно хороший пример этого. Проверьте этот ответ для получения дополнительной информации. Резюме:

  1. Страница начинается
  2. Все параметры загружаются с простым SELECT option_name, option_value from $wpdb->optionsзаявлением
  3. Последующие запросы на эти параметры (например, вызов get_optionникогда не попадет в базу данных, поскольку они хранятся в API-интерфейсе кэширования WP).

Опции всегда «живут» в базе данных и всегда сохраняются там - это их «канонический» источник. Тем не менее, опции загружаются в кеш объекта, поэтому при запросе опции есть 99% вероятность того, что запрос никогда не попадет в базу данных.

Переходные процессы немного отличаются.

WordPress позволяет заменить API-интерфейс кеша на раскрывающийся файл - файл, который помещается непосредственно в вашу wp-contentпапку. Если вы создаете свой собственный кеш или добавляете существующий плагин , вы можете сделать так, чтобы кеш объектов сохранялся дольше, чем загрузка одной страницы. Когда вы это сделаете, переходные процессы немного изменятся.

Давайте посмотрим на set_transientфункцию в wp-includes/option.php.

<?php
/**
 * Set/update the value of a transient.
 *
 * You do not need to serialize values. If the value needs to be serialized, then
 * it will be serialized before it is set.
 *
 * @since 2.8.0
 * @package WordPress
 * @subpackage Transient
 *
 * @uses apply_filters() Calls 'pre_set_transient_$transient' hook to allow overwriting the
 *  transient value to be stored.
 * @uses do_action() Calls 'set_transient_$transient' and 'setted_transient' hooks on success.
 *
 * @param string $transient Transient name. Expected to not be SQL-escaped.
 * @param mixed $value Transient value. Expected to not be SQL-escaped.
 * @param int $expiration Time until expiration in seconds, default 0
 * @return bool False if value was not set and true if value was set.
 */
function set_transient( $transient, $value, $expiration = 0 ) {
    global $_wp_using_ext_object_cache;

    $value = apply_filters( 'pre_set_transient_' . $transient, $value );

    if ( $_wp_using_ext_object_cache ) {
        $result = wp_cache_set( $transient, $value, 'transient', $expiration );
    } else {
        $transient_timeout = '_transient_timeout_' . $transient;
        $transient = '_transient_' . $transient;
        if ( false === get_option( $transient ) ) {
            $autoload = 'yes';
            if ( $expiration ) {
                $autoload = 'no';
                add_option( $transient_timeout, time() + $expiration, '', 'no' );
            }
            $result = add_option( $transient, $value, '', $autoload );
        } else {
            if ( $expiration )
                update_option( $transient_timeout, time() + $expiration );
            $result = update_option( $transient, $value );
        }
    }
    if ( $result ) {
        do_action( 'set_transient_' . $transient );
        do_action( 'setted_transient', $transient );
    }
    return $result;
}

Хммм $_wp_using_ext_object_cache? Если это правда, WordPress использует кеш объекта вместо базы данных для хранения переходных процессов. Так как же это установить на истину? Пришло время изучить, как WP настраивает свой собственный API кеша.

Вы можете отследить практически все до wp-load.phpили wp-settings.php- оба из них имеют решающее значение для процесса начальной загрузки WordPress. В нашем кеше есть несколько соответствующих строк wp-settings.php.

// Start the WordPress object cache, or an external object cache if the drop-in is present.
wp_start_object_cache();

Помните это падение сверху? Давайте посмотрим на wp_start_object_cacheв wp-includes/load.php.

<?php
/**
 * Starts the WordPress object cache.
 *
 * If an object-cache.php file exists in the wp-content directory,
 * it uses that drop-in as an external object cache.
 *
 * @access private
 * @since 3.0.0
 */
function wp_start_object_cache() {
    global $_wp_using_ext_object_cache, $blog_id;

    $first_init = false;
    if ( ! function_exists( 'wp_cache_init' ) ) {
        if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
            require_once ( WP_CONTENT_DIR . '/object-cache.php' );
            $_wp_using_ext_object_cache = true;
        } else {
            require_once ( ABSPATH . WPINC . '/cache.php' );
            $_wp_using_ext_object_cache = false;
        }
        $first_init = true;
    } else if ( !$_wp_using_ext_object_cache && file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
        // Sometimes advanced-cache.php can load object-cache.php before it is loaded here.
        // This breaks the function_exists check above and can result in $_wp_using_ext_object_cache
        // being set incorrectly. Double check if an external cache exists.
        $_wp_using_ext_object_cache = true;
    }

    // If cache supports reset, reset instead of init if already initialized.
    // Reset signals to the cache that global IDs have changed and it may need to update keys
    // and cleanup caches.
    if ( ! $first_init && function_exists( 'wp_cache_switch_to_blog' ) )
        wp_cache_switch_to_blog( $blog_id );
    else
        wp_cache_init();

    if ( function_exists( 'wp_cache_add_global_groups' ) ) {
        wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache' ) );
        wp_cache_add_non_persistent_groups( array( 'comment', 'counts', 'plugins' ) );
    }
}

Соответствующие строки функции (те, которые относятся к $_wp_using_ext_object_cacheэтому, изменяют способ хранения переходных процессов).

if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
    require_once ( WP_CONTENT_DIR . '/object-cache.php' );
    $_wp_using_ext_object_cache = true;
} else {
    require_once ( ABSPATH . WPINC . '/cache.php' );
    $_wp_using_ext_object_cache = false;
}

если он object-cache.phpсуществует в вашем каталоге содержимого, он включается, и WP предполагает, что вы используете внешний постоянный кеш - он устанавливает$_wp_using_ext_object_cache значение true.

Если вы используете внешние объекты кеша переходные процессы будут использовать его. Что поднимает вопрос о том, когда использовать параметры против переходных процессов.

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

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

Некоторые другие проблемы / вопросы:

  1. Можно ли делать кучу звонков get_option? Вероятно. Они вызывают вызов функции, но, скорее всего, не попадут в базу данных. Загрузка базы данных часто является более серьезной проблемой в масштабируемости веб-приложений, чем работа, которую ваш язык делает для создания страницы.
  2. Как я знаю, чтобы использовать переходные процессы по сравнению с Cache API? Если вы ожидаете, что данные сохранятся в течение заданного периода, используйте переходный API. Если не имеет значения, сохраняются ли данные (например, это не займет много времени для вычисления / извлечения данных, но это не должно происходить более одного раза за загрузку страницы), используйте API-интерфейс кэширования.
  3. Все ли параметры действительно кэшируются при каждой загрузке страницы? Не обязательно. Если вы вызываете add_optionс последним необязательным аргументом, поскольку noони не загружаются автоматически. Тем не менее, как только вы получите их один раз, они попадут в кеш, и последующие вызовы не попадут в базу данных.
chrisguitarguy
источник
Нитпик 1: Не все опции загружаются при запуске страницы, но только те, которые помечены как «autoload = yes» при создании. Значением по умолчанию для этого параметра в add_option является «да», и большинство авторов плагинов не заботятся о том, чтобы понять разницу в использовании «нет», что делает ваше утверждение практически верным.
Марк Каплун
Даже неавтоматизированные параметры кэшируются после их выборки один раз. Они могут быть не загружены изначально, но после этого они попадают в кэш объектов. Даже параметры, которые не существуют, кэшируются! github.com/WordPress/WordPress/blob/master/wp-includes/… Однако я добавил примечание об опции автозагрузки.
chrisguitarguy
это было придирчиво 2;)
Марк Каплун
Спасибо за отличную статью и за то, что подвели итоги.
прости
5

Есть 4 типа кэша, о которых я знаю

  1. Trivial - он всегда включен и вступает в силу до того, как в игру вступит любое другое кэширование. Он хранит кэшированные элементы в массиве php, что означает, что он потребляет память из сеанса выполнения php, и что кэш очищается после завершения выполнения php. т. е. даже без использования какого-либо другого кэша, если вы вызываете get_option ('opt') дважды подряд, вы будете выполнять запрос к БД только в первый раз, а во второй раз значение будет возвращено из памяти.

  2. Файл - кэшированные значения хранятся в файлах где-то в вашем корневом каталоге. Я считаю, что это оказалось неэффективным с точки зрения производительности, если у вас не очень быстрое дисковое или картографическое хранилище файлов.

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

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

Кстати, кеширование объектов - это гораздо больше, чем просто кеширование, оно будет хранить практически все, что было извлечено из БД с использованием высокоуровневого WP API.

Марк Каплун
источник
Я знаю, что ответ довольно старый, но я бы добавил также отличный Redis .
Cranio
@Cranio, вы правы, но ... redis - это, по сути, вариант memcache с хранилищем, и, следовательно, это (NoSQL) DB. Это IMHO на самом деле плохо, так как если узел выходит из строя или не может быть обновлен, вы можете получить устаревшую информацию из него. У него есть возможность отключить поведение, подобное БД, но я не уверен, включено ли оно по умолчанию.
Марк Каплун
Это идеальная замена Memcached (даже лучше), что еще нужно? Безусловно, наиболее распространенное использование, которое я видел, - это просто хранение значений ключа ОЗУ (да, кроме этого, данные можно сделать постоянными, кластеризация идет, и есть возможности управления очередью, но каждый добавляет Redis как отличный опция кеширования для WP)
Cranio
каждый может также прыгнуть с моста;) но дополнительная сложность совершенно не нужна для кеширования
Марк Каплун,
Это совершенно бессмысленно; вы хотите кеширование ОЗУ, Redis делает кеширование RAM, точка; и это делает это чудесно. Там нет абсолютно никакой дополнительной сложности, если вы не хотите идти на это. Итак, сэр, я действительно не понимаю вашу точку зрения.
Cranio
0

Опции всегда хранятся в базе данных, а переходные процессы могут храниться только в разделяемой памяти, если установлен APC и плагин, который реализует кэширование APC в WP. Memcache также использует память.

Опции также хранятся в памяти и по возможности загружаются оттуда (если нет, выполняется запрос в БД).

onetrickpony
источник
0

Отличный вопрос

Я думаю, что часть с тем, как WordPress использует WP_Object_Cache класс, все еще отсутствует, поэтому я добавлю это.

Из документов:

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

Вот WP_Object_Cacheструктура.

введите описание изображения здесь

Примечание + является общедоступным, - частным, # защищенным.

Этот stats()метод используется для отображения общей статистики об объекте глобального кэша и о том, что там находится. Вот вывод:

Cache Hits: 110
Cache Misses: 98

Group: options - ( 81.03k )
Group: default - ( 0.03k )
Group: users - ( 0.41k )
Group: userlogins - ( 0.03k )
Group: useremail - ( 0.04k )
Group: userslugs - ( 0.03k )
Group: user_meta - ( 3.92k )
Group: posts - ( 1.99k )
Group: terms - ( 1.76k )
Group: post_tag_relationships - ( 0.04k )
Group: category_relationships - ( 0.03k )
Group: post_format_relationships - ( 0.02k )
Group: post_meta - ( 0.36k )

Это то, что я получил раньше в самом начале шаблона, такого как single.php .

Обратите внимание на интересующую нас переменную: global $wp_object_cache .

Закрытый член $cacheхранит фактические данные кэширования.

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

Так как я был, single.phpкогда я напечатал кеш:

print_r($wp_object_cache->cache['posts']);

Я получаю один пост в кэше.

    [last_changed] => 0.34169600 1481802075
    [get_page_by_path:2516f01e446b6c125493ec7824b63868:0.34169600 1481802075] => 0
    [2831] => WP_Post Object
        (
            [ID] => 2831
            [post_author] => 1 
            ... the cached post object goes here
        )

Объектом будет значение, а ключ кэширования будет

get_page_by_path:2516f01e446b6c125493ec7824b63868:0.34169600 1481802075

Здесь вы можете проверить $cache_keyструктуру:

File: /wp-includes/post.php
4210: /**
4211:  * Retrieves a page given its path.
4212:  *
4213:  * @since 2.1.0
4214:  *
4215:  * @global wpdb $wpdb WordPress database abstraction object.
4216:  *
4217:  * @param string       $page_path Page path.
4218:  * @param string       $output    Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
4219:  *                                a WP_Post object, an associative array, or a numeric array, respectively. Default OBJECT.
4220:  * @param string|array $post_type Optional. Post type or array of post types. Default 'page'.
4221:  * @return WP_Post|array|null WP_Post (or array) on success, or null on failure.
4222:  */
4223: function get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) {
4224:   global $wpdb;
4225: 
4226:   $last_changed = wp_cache_get_last_changed( 'posts' );
4227: 
4228:   $hash = md5( $page_path . serialize( $post_type ) );
4229:   $cache_key = "get_page_by_path:$hash:$last_changed";
4230:   $cached = wp_cache_get( $cache_key, 'posts' );
4231:   if ( false !== $cached ) {
4232:       // Special case: '0' is a bad `$page_path`.
4233:       if ( '0' === $cached || 0 === $cached ) {
4234:           return;
4235:       } else {
4236:           return get_post( $cached, $output );
4237:       }
4238:   }
прости
источник