Como o cache de objetos funciona?

21

Estou procurando uma resposta definitiva aqui. Quando o cache de objetos está ativado, onde opções e transitórios acabam sendo exibidos?

Por padrão, ambos são armazenados no banco de dados. Mas ouvi algumas referências de que o memcache as armazenará em outros lugares e a APC fará outra coisa completamente. Onde, exatamente , esses dados serão mantidos nos dois casos?

EAMann
fonte
2
O artigo @toscho menciona agora está disponível no archive.org: Explorando a API de cache do WordPress
aqui

Respostas:

34

O WordPress, por padrão, faz uma forma de "Cache de Objeto", mas sua vida útil é apenas um carregamento de página única.

As opções são realmente um bom exemplo disso. Confira esta resposta para mais informações. O sumário:

  1. Uma página começa
  2. Todas as opções são carregadas com uma SELECT option_name, option_value from $wpdb->optionsdeclaração simples
  3. Solicitações subsequentes para essas opções (por exemplo, uma chamada para get_optionnunca atingir o banco de dados porque elas são armazenadas com a API de cache do WP.

As opções sempre "vivem" no banco de dados e sempre persistem lá - essa é a fonte "canônica". Dito isso, as opções são carregadas no cache do objeto; portanto, quando você solicita uma opção, há 99% de chance de a solicitação nunca atingir o banco de dados.

Os transientes são um pouco diferentes.

O WordPress permite que você substitua a API do cache por um drop-in - um arquivo que é colocado diretamente na sua wp-contentpasta. Se você criar seu próprio cache ou usar um plug-in existente , poderá fazer com que o cache do objeto persista por mais tempo que um único carregamento de página. Quando você faz isso, transitório, mude um pouco.

Vamos dar uma olhada na set_transientfunção 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;
}

Humm $_wp_using_ext_object_cache? Se for verdade, o WordPress usa o cache de objetos em vez do banco de dados para armazenar transitórios. Então, como isso é definido? Hora de explorar como o WP configura sua própria API de cache.

Você pode rastrear quase tudo para wp-load.phpou wp-settings.php- os quais são cruciais para o processo de inicialização do WordPress. Em nosso cache, existem algumas linhas relevantes wp-settings.php.

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

Lembra daquela queda de cima? Vamos dar uma olhada wp_start_object_cacheem 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' ) );
    }
}

As linhas relevantes da função (aquelas que pertencem a $_wp_using_ext_object_cacheisso alteram como os transientes são armazenados).

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;
}

se object-cache.phpexistir no diretório de conteúdo, ele será incluído e o WP assume que você está usando um cache externo persistente - ele é definido $_wp_using_ext_object_cachecomo true.

Se você estiver usando um cache de objeto externo, os transientes o usarão. O que levanta a questão de quando usar opções versus transientes.

Simples. Se você precisar que os dados persistam indefinidamente, use as opções. Eles são "armazenados em cache", mas suas fontes canônicas são o banco de dados e nunca desaparecem, a menos que um usuário solicite explicitamente.

Para dados que devem ser armazenados por um período de tempo definido, mas não precisam persistir além de um tempo de vida útil especificado. Internamente, o WP tentará usar um cache de objeto externo e persistente, caso contrário, os dados entrarão na tabela de opções e serão coletados como lixo através do psuedo-cron do WordPress quando expirarem.

Algumas outras preocupações / perguntas:

  1. Tudo bem fazer uma tonelada de chamadas get_option? Provavelmente. Eles incorrem na chamada para uma sobrecarga de função, mas provavelmente não atingirá o banco de dados. O carregamento do banco de dados geralmente é uma preocupação maior na escalabilidade de aplicativos da Web do que o trabalho que seu idioma preferido gera para gerar uma página.
  2. Como sei usar transitórios versus a API de cache? Se você espera que os dados persistam por um período definido, use a API transitória. Se não importa se os dados persistem (por exemplo, não demora muito para computar / buscar os dados, mas não deve ocorrer mais de uma vez por carregamento da página), use a API de cache.
  3. Todas as opções são realmente armazenadas em cache em cada carregamento de página? Não necessariamente. Se você chamar add_optioncom o último argumento opcional, pois noeles não são carregados automaticamente. Dito isto, depois de buscá-los uma vez, eles entram no cache e as chamadas subseqüentes não atingem o banco de dados.
chrisguitarguy
fonte
nitpick 1: nem todas as opções são carregadas no início da página, mas apenas aquelas marcadas com "carregamento automático = sim" quando criadas. O padrão para esse parâmetro em add_option é 'yes' e a maioria dos criadores de plugins não se preocupa em entender a diferença de usar um 'não', tornando sua afirmação praticamente verdadeira.
precisa
Mesmo as opções não carregadas automaticamente são armazenadas em cache após serem buscadas uma vez. Eles podem não ser carregados inicialmente, mas vão para o cache de objetos depois disso. Até as opções que não existem são armazenadas em cache! github.com/WordPress/WordPress/blob/master/wp-includes/… No entanto , adicionei uma observação sobre a opção de carregamento automático.
Chrisguitarguy 3/12/12
que foi nitpick 2;) #
27468 Mark Kaplun
Obrigado pelo ótimo artigo e pelo tempo que resume tudo isso.
Prosti15:
5

Existem 4 tipos de cache que eu conheço

  1. Trivial - Está sempre ativado e entra em vigor antes de qualquer outro armazenamento em cache. Ele armazena os itens em cache em um array php, o que significa que consome memória da sua sessão de execução php e que o cache é esvaziado após o término da execução do php. ou seja, mesmo sem usar outro cache, se você chamar get_option ('opt') duas vezes seguidas, fará uma consulta ao banco de dados somente na primeira e na segunda vez em que o valor será retornado da memória.

  2. Arquivo - valores em cache são armazenados em arquivos em algum lugar no diretório raiz. Acredito que ele provou não ser eficaz em termos de desempenho, a menos que você tenha um armazenamento de arquivos mapeado em disco ou memória muito rápido.

  3. APC (ou outro cache baseado em acelerador php) - Os valores em cache são armazenados na memória da máquina host e fora da alocação de memória php. A maior armadilha em potencial é que não há escopo de dados e, se você executar dois sites, potencialmente cada um poderá acessar os dados em cache do outro ou substituí-los.

  4. Memcache - é um cache baseado em rede. Você pode executar o serviço de armazenamento em cache em qualquer lugar da rede e provavelmente armazena valores na memória do host. Você provavelmente não precisa do memcache, a menos que tenha um balanceamento de carga em ação.

BTW, o cache de objetos está armazenando em cache muito mais do que opções, ele armazenará quase tudo que foi recuperado do banco de dados usando a API WP de alto nível.

Mark Kaplun
fonte
Eu sei que a resposta é bastante antiga, mas gostaria de acrescentar também os excelentes Redis .
precisa
@Cranio, você está certo, mas ... redis é basicamente uma variante do memcache com armazenamento e, portanto, é um banco de dados (NoSQL). Esse IMHO é realmente ruim, como se o nó falhasse ou não pudesse ser atualizado, você pode obter informações obsoletas dele. Ele tem uma opção para desativar o comportamento semelhante ao banco de dados, mas não tenho certeza se está ativado ou desativado por padrão.
Mark Kaplun
É um substituto perfeito para o Memcached (melhor ainda), o que mais você precisa? De longe, o uso mais comum que eu vi é o armazenamento de valores-chave da RAM (sim, além disso, os dados podem ser persistentes, o cluster está a caminho e possui recursos de gerenciamento de filas, mas todos adicionam o Redis como um excelente opção de cache para WP)
Cranio 12/04
todos também pode saltar da ponte;) mas a complexidade totalmente não é necessário para caching
Mark Kaplun
Isso é completamente inútil; você quer cache de RAM, Redis faz cache de RAM, ponto final; e faz isso maravilhosamente. Não absolutamente nenhuma complexidade adicional se você não quiser fazer isso. Então, senhor, eu realmente não entendo o seu ponto.
Cranio
0

As opções são sempre armazenadas no banco de dados, enquanto os transitórios podem ser armazenados apenas na memória compartilhada se o APC e um plug-in que implementa o cache do APC no WP estiverem instalados. Memcache também usa memória.

As opções também são armazenadas na memória e carregadas a partir daí quando possível (se não, uma consulta db é executada).

onetrickpony
fonte
0

Ótima pergunta.

Eu acho que WP_Object_Cacheainda falta a parte de como o WordPress usa a classe, então vou acrescentar isso.

Dos documentos:

DEF: O cache de objetos do WordPress é usado para salvar em viagens ao banco de dados. O Cache de Objeto armazena todos os dados do cache na memória e disponibiliza o conteúdo do cache usando uma chave, usada para nomear e recuperar posteriormente o conteúdo do cache.

Aqui está a WP_Object_Cacheestrutura.

insira a descrição da imagem aqui

Nota + é público, - privado, # protegido.

Você usa o stats()método para mostrar estatísticas gerais sobre o objeto de cache global e o que há nele. Aqui está a saída:

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 )

Foi o que obtive antes no início de um modelo como single.php.

Observe a variável que nos interessa é: global $wp_object_cache.

O privado que o membro $cachemantém os dados reais de armazenamento em cache.

Na programação, as estruturas de cache estão por toda parte. De uma forma simples, eles podem ser reconhecidos como um par de valores-chave. Caçambas, estruturas NoDB, índices de banco de dados. O objetivo final do WordPress Object Cache não era ter a estrutura mais simples possível, mas ainda assim os pares de valores-chave podem ser reconhecidos.

Desde que eu estava single.phpquando imprimi o cache:

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

Estou recebendo uma única postagem em cache.

    [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
        )

O objeto seria o valor e a chave de armazenamento em cache seria

get_page_by_path:2516f01e446b6c125493ec7824b63868:0.34169600 1481802075

Aqui você pode conferir a $cache_keyestrutura:

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:   }
prosti
fonte