Como funciona o cache de objetos?

20

Estou procurando uma resposta definitiva aqui. Quando o cache de objetos está habilitado, onde as opções e os transientes acabam vivendo?

Por padrão, ambos são armazenados no banco de dados. Mas eu ouvi algumas referências que o memcache irá armazená-las em outro lugar e a APC fará algo totalmente diferente. Onde, exatamente , esses dados serão mantidos em ambos os casos?

    
por EAMann 02.12.2012 / 22:23

4 respostas

31

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

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

  1. Uma página começa
  2. Todas as opções são carregadas com uma simples declaração SELECT option_name, option_value from $wpdb->options
  3. Pedidos subseqüentes para essas opções (por exemplo, uma chamada para get_option nunca atingiu o banco de dados porque eles são armazenados com a API do cache do WP.

As opções sempre "vivem" no banco de dados e são sempre persistidas lá - essa é a fonte "canônica". Dito isso, as opções são carregadas no cache de objetos, então, quando você solicita uma opção, há 99% de chance de que a solicitação nunca atinja 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 pasta wp-content . Se você criar seu próprio cache, use ou use um existente plugin , você pode fazer o cache de objetos persistir mais do que um único carregamento de página. Quando você faz isso, transientes, mudam um pouco.

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

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

Você pode rastrear quase tudo para wp-load.php ou wp-settings.php - ambos são cruciais para o processo de bootstrap do WordPress. Em nosso cache, existem algumas linhas relevantes em wp-settings.php .

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

Lembre-se da queda na coisa de cima? Vamos dar uma olhada em wp_start_object_cache em 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 ao $_wp_using_ext_object_cache que altera 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.php existir em seu diretório de conteúdo, ele será incluído e o WP assumirá que você está usando um cache externo persistente - define $_wp_using_ext_object_cache como verdadeiro.

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

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

Para dados que devem ser armazenados por um determinado período de tempo, mas não precisam persistir além de um tempo de vida especificado, use transientes. 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 obterão o lixo coletado por meio de WordPress 'psuedo-cron quando eles expiram.

Algumas outras preocupações / perguntas:

  1. Não há problema em fazer uma tonelada de chamadas para get_option ? Provavelmente. Eles incorrem na chamada para uma sobrecarga de função, mas provavelmente não atingirão o banco de dados. A carga do banco de dados costuma ser uma preocupação maior na escalabilidade do aplicativo da Web do que o trabalho que o idioma de sua escolha gera uma página.
  2. Como eu sei usar transientes versus a API 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 isso não deve acontecer mais de uma vez por carregamento de página) use a API de cache.
  3. Todas as opções são realmente armazenadas em cache em cada pageload? Não necessariamente. Se você chamar add_option com seu último argumento opcional como no , eles não serão carregados automaticamente. Dito isso, uma vez que você os busca uma vez, eles vão para o cache e as chamadas subsequentes não atingem o banco de dados.
por chrisguitarguy 03.12.2012 / 06:19
5

Existem 4 tipos de cache que conheço

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

  2. Arquivo - Os valores armazenados em cache são armazenados em arquivos em algum lugar no diretório raiz. Acredito que não tenha sido 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 armazenamento em cache baseado no acelerador php) - Os valores armazenados em cache são armazenados na memória da máquina host e fora da alocação de memória do seu php. A maior armadilha potencial é que não há escopo de dados e, se você executar dois sites, cada um pode acessar os dados em cache do outro, ou sobrescrevê-lo.

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

BTW, o cache de objeto 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.

    
por Mark Kaplun 03.12.2012 / 06:13
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 plugin que implementa o cache APC no WP estiver instalado. O Memcache também usa memória.

As opções também são armazenadas na memória e carregadas de lá quando possível (se não, uma consulta do banco de dados é executada).

    
por onetrickpony 03.12.2012 / 05:54
0

Grande pergunta.

Acho que a parte com a qual o WordPress usa a WP_Object_Cache class ainda está faltando, então vou acrescentar isso.

Nos documentos:

  

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

Aqui está a estrutura WP_Object_Cache .

  

Anota+épública,-privada,#protegida.

Vocêusaométodostats()paramostrarestatísticasgeraissobreoobjetodecacheglobaleoqueestálá.Aquiestáasaída:

CacheHits:110CacheMisses:98Group: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)

Issoéoqueobtiveantesnoiníciodeummodelo,comosingle.php.

Observequeavariávelquenosinteressaé:global$wp_object_cache.

Omembroprivado,omembro$cache,contémosdadosreaisdearmazenamentoemcache.

  

Naprogramação,asestruturasdecacheestãoemtodolugar.Deumaformasimples,elespodemserreconhecidoscomoumpardevalores-chave.Buckets,estruturasNoDB,índicesdebancodedados.OobjetivofinaldoCachedeObjetosdoWordPressnãoerateraestruturamaissimplespossível,masosparesdevalores-chaveaindapodemserreconhecidos.

Comoestavaemsingle.phpquandoimprimiocache:

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

Estourecebendoumúnicopostemcache.

[last_changed]=>0.341696001481802075[get_page_by_path:2516f01e446b6c125493ec7824b63868:0.341696001481802075]=>0[2831]=>WP_PostObject([ID]=>2831[post_author]=>1...thecachedpostobjectgoeshere)

Oobjetoseriaovalor,eachavedecacheseria

get_page_by_path:2516f01e446b6c125493ec7824b63868:0.341696001481802075

Aquivocêpodeverificaraestrutura$cache_key:

File:/wp-includes/post.php4210:/**4211:*Retrievesapagegivenitspath.4212:*4213:*@since2.1.04214:*4215:*@globalwpdb$wpdbWordPressdatabaseabstractionobject.4216:*4217:*@paramstring$page_pathPagepath.4218:*@paramstring$outputOptional.Therequiredreturntype.OneofOBJECT,ARRAY_A,orARRAY_N,whichcorrespondto4219:*aWP_Postobject,anassociativearray,oranumericarray,respectively.DefaultOBJECT.4220:*@paramstring|array$post_typeOptional.Posttypeorarrayofposttypes.Default'page'.4221:*@returnWP_Post|array|nullWP_Post(orarray)onsuccess,ornullonfailure.4222:*/4223:functionget_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:   }
    
por prosti 15.12.2016 / 14:53