Як працює кешування об'єктів?


21

Я шукаю остаточну відповідь тут. Коли кешоване об'єктом увімкнено, де параметри та перехідні процеси закінчуються?

За замовчуванням обидва зберігаються в базі даних. Але я чув деякі посилання на те, що пам’ять зберігатиме їх в іншому місці, і APC буде робити щось інше цілком. Де саме ці дані зберігатимуться в обох випадках?


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. Як я можу використовувати перехідні програми та API кешу? Якщо ви очікуєте, що дані зберігатимуться протягом встановленого періоду, використовуйте перехідний API. Якщо не важливо, чи зберігаються дані (наприклад, для обчислення / отримання даних не потрібно багато часу, але це не повинно відбуватися більше одного разу на завантаження сторінки), використовуйте API кешу.
  3. Чи дійсно всі параметри кешовано на кожному завантаженні сторінки? Не обов'язково. Якщо ви телефонуєте add_optionз останнім, необов'язковим аргументом, оскільки noвони не завантажуються автоматично. Однак, як тільки ви їх отримаєте один раз, вони входять у кеш і наступні дзвінки не потраплять до бази даних.

nitpick 1: Не всі параметри завантажуються при запуску сторінки, але лише ті, які позначені "autoload = так" при створенні. За замовчуванням для цього параметра в add_option є "так", і більшість авторів плагінів не намагаються зрозуміти різницю у використанні "ні", і це робить ваше твердження практично істинним.
Марк Каплун

Навіть опції, які не завантажуються автоматично, кешуються після їх отримання один раз. Вони можуть не завантажуватися спочатку, але після цього вони переходять у кеш об'єктів. Навіть параметри, які не існують, є кешованими! github.com/WordPress/WordPress/blob/master/wp-includes/… Я додав примітку про опцію автоматичного завантаження.
chrisguitarguy

це був нитпік 2;)
Марк Каплун

Дякую за чудову статтю та за час, що підсумовує все це.
prosti

5

Існує 4 типи кеша, які я знаю

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

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

  3. APC (або інше кешування на основі прискорювача php) - кешовані значення зберігаються в пам'яті вашого хост-машини та поза вашим розподілом пам'яті php. Найбільша потенційна проблема полягає в тому, що немає масштабування даних і якщо ви запускаєте два сайти, кожен може отримати доступ до кешованих даних іншого або перезаписати їх.

  4. Memcache - це кеш на основі мережі. Ви можете запустити службу кешування будь-де в мережі, і він, ймовірно, зберігає значення у своїй хост-пам'яті. Ви, мабуть, не потребуєте мемкеш, якщо у вас не відбувається балансування навантаження в дії.

До речі, кешування об'єктів кешується набагато більше, ніж опції, воно зберігатиме майже все, що було отримано з БД за допомогою API високого рівня WP.


Я знаю, що відповідь досить стара, але я б додав також відмінний Redis .
Краніо

@Cranio, ти маєш рацію, але ... redis - це в основному варіант пам’яті зі сховищем, і для цього це (NoSQL) БД. Цей IMHO насправді поганий, так як якщо вузол виходить з ладу або не може бути оновлений, ви можете отримати від нього застарілу інформацію. У нього є можливість вимкнути поведінку типу БД, але я не впевнений, чи він увімкнено або вимкнено за замовчуванням.
Марк Каплун

Це ідеальна заміна Memcached (ще краще), що ще потрібно? На сьогодні найпоширеніше використання, яке я бачив, - це просто зберігання ключових значень оперативної пам’яті (так, крім цього, дані можна зробити стійкими, кластеризація працює і має можливості управління чергою, але кожен додає Redis як відмінний варіант кешування для WP)
Cranio

всі також можуть стрибати з мосту;) але додаткова складність зовсім не потрібна для кешування
Марк Каплун

Це абсолютно безглуздо; ви хочете кешування оперативної пам'яті, Redis робить кешування оперативної пам'яті, період; і це робить це чудово. Там абсолютно немає додаткової складності, якщо ви не хочете на це піти. Отже, сер, я дійсно не розумію вашого погляду.
Краніо

0

Опції завжди зберігаються в базі даних, тоді як перехідні періоди можуть зберігатися лише у спільній пам'яті, якщо встановлено APC та плагін, що реалізує кешування APC у WP. Memcache також використовує пам'ять.

Опції також зберігаються в пам'яті та завантажуються звідти, коли це можливо (якщо ні, виконується запит db).


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:   }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.