Devo usar a API transitória para armazenar HTML String ou Object?

18

Vamos supor que haja um plug-in que exibe 20 postagens relacionadas (para cada post) com uma consulta muito complexa. E então, usando os dados dessa consulta, ele cria um layout HTML complexo. Além disso, deve-se notar que o plug-in é público e pode ser instalado em qualquer servidor com qualquer configuração.

Algo como:

/* 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 .= ...;
}

Então, minhas perguntas são:

  • Qual é a maneira mais segura e correta de armazenar em cache esses dados?
  • Devo usar a API transitória para armazenar em cache a $related_postsmatriz ou a $html_outputstring? Se eu armazenar em cache a $html_ouputstring, ela atingirá algum limite de tamanho máximo? Talvez eu deva apertá-lo antes de salvar?
  • Devo usar a API transitória aqui?
Marvin3
fonte

Respostas:

18

Devo usar a API transitória aqui?

Não.

Em um estoque, os transitórios de instalação do WordPress são armazenados na tabela wp_options e limpos apenas durante as atualizações principais. Suponha que você tenha 50.000 postagens, ou seja, 50.000 linhas adicionais na tabela de opções. Obviamente, eles estão configurados para autoload = no, portanto não consumirá toda a sua memória, mas há outra ressalva.

O campo de carregamento automático na tabela de opções não possui um índice, o que significa que a chamada wp_load_alloptions()para realizará uma varredura completa da tabela. Quanto mais linhas você tiver, mais tempo levará. Quanto mais você escreve na tabela de opções, menos são os caches internos do MySQL.

Se os dados em cache estiverem diretamente relacionados a uma postagem, é melhor armazená-los na meta meta. Isso também salvará uma consulta sempre que você precisar exibir o conteúdo em cache, porque os meta-caches de postagem são (geralmente) preparados durante a recuperação de postagem no WP_Query.

Sua estrutura de dados para o meta-valor pode variar, você pode ter um carimbo de data e hora e executar sua consulta cara se o valor em cache estiver desatualizado, como um comportamento temporário.

Outro pensamento importante a ter em mente é que os transientes do WordPress podem ser voláteis em ambientes com cache de objetos persistente. Isso significa que, se você armazenar seus dados em cache por 24 horas em um transitório, não há absolutamente nenhuma garantia de que eles estarão disponíveis em 23 horas ou 12 ou até 5 minutos. O back-end do cache de objetos para muitas instalações é um armazenamento de valores-chave na memória, como Redis ou Memcached, e se não houver memória alocada suficiente para caber em objetos mais recentes, os itens mais antigos serão despejados. Esta é uma grande vitória para a abordagem de meta armazenamento.

A invalidação também pode ser mais inteligente, ou seja, por que você está invalidando os caches de postagens relacionadas em X horas? É porque algum conteúdo mudou? Uma nova postagem foi adicionada? Uma nova tag foi atribuída? Dependendo da sua "consulta complexa e grande", você pode optar por invalidar SOMENTE se algo acontecer que altere os resultados da sua consulta.

Devo usar a API transitória para armazenar em cache a matriz $ related_posts ou a cadeia $ html_output? Se eu armazenar em cache a string $ html_ouput, ela atingirá algum limite de tamanho máximo? Talvez eu deva apertá-lo antes de salvar?

Depende muito do tamanho da sua string, já que esses são os dados que fluirão entre PHP, MySQL, etc. Você precisará tentar muito atingir os limites do MySQL, mas, por exemplo, o limite padrão por objeto do Memcached é apenas 1 mb.

Quanto tempo sua "lógica de renderização de layout complexo" realmente leva? Execute-o através de um criador de perfil para descobrir. As chances são de que seja muito rápido e nunca se tornará um gargalo.

Se for esse o caso, sugiro armazenar em cache os IDs de postagem. Não os objetos WP_Post, porque eles conterão o conteúdo completo da postagem, mas apenas uma matriz de IDs da postagem. Em seguida, basta usar um WP_Querycom um post__inque resultará em uma consulta MySQL muito rápida por chave primária.

Dito isto, se os dados necessários por item forem bastante simples, talvez título, URL da miniatura e link permanente, você poderá armazenar apenas esses três, sem a sobrecarga de uma viagem de ida e volta extra ao MySQL, e sem a sobrecarga de armazenar em cache HTML muito longo cordas.

Uau, são muitas palavras, espero que ajude.

kovshenin
fonte
12

Nem todo código WP é código público

Se você vai divulgar algo público, todas as coisas que kovshenin disse são perfeitamente válidas.

As coisas são diferentes se você escrever um código privado para você ou sua empresa.

O cache de objetos externos é um grande benefício, em qualquer caso

É muito recomendável definir um cache de objeto persistente externo , quando possível.

Todas as coisas ditas na resposta do kovshenin sobre transientes e MySQL são muito verdadeiras, e considerando que o próprio WP e vários plugins fazem uso do cache de objetos ... então a melhoria de desempenho obtida, vale absolutamente o (pequeno) esforço de configuração um sistema de cache moderno como Redis ou Memcached.

Valores em cache podem não estar lá: tudo bem

Além disso, sim, um cache de objeto externo não é confiável. Você nunca deve confiar no fato de que existe um transitório. Você precisa garantir que funcione se o cache não estiver onde deveria estar.

Cache não é armazenamento, cache é cache.

Usar cache seletivamente

Veja este exemplo:

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

Usando um código como esse, em seu site privado, o desempenho do site pode melhorar muito , principalmente se você tiver muitos usuários.

Observe que:

  • Por padrão, o cache não é usado quando a depuração está ativada, assim esperançosamente em seu ambiente de desenvolvimento. Acredite, o cache pode tornar a depuração um inferno
  • Por padrão, o cache também não é usado quando o WP não está configurado para usar um cache de objeto externo. Isso significa que todo o problema conectado ao MySQL não existe, porque você não usa transitórios quando eles usam o MySQL. Uma alternativa provavelmente mais fácil seria usar wp_cache_*funções ; portanto, se nenhum cache externo estiver configurado, o cache ocorrerá na memória e o banco de dados nunca estará envolvido.
  • O uso do cache é filtrável, para lidar com alguns casos extremos que você pode encontrar

Sem escala da Web se não houver cache

Você não deve tentar resolver problemas de velocidade com o cache. Se você tiver problemas de velocidade, deve repensar o código.

Mas, para dimensionar um site em escala da web, o cache é bastante necessário .

E muitas vezes (mas nem sempre) fragmentam, o cache sensível ao contexto é muito mais flexível e adequado do que o cache agressivo de página inteira.

Suas perguntas:

Devo usar a API transitória aqui?

Depende .

Seu código está consumindo muitos recursos? Caso contrário, talvez não haja necessidade de cache. Como dito, não é apenas uma questão de velocidade. Se o seu código é rápido, mas requer muita CPU e memória para alguns usuários ... o que acontece quando você tem 100 ou 1000 usuários simultâneos?

Se você perceber que o cache seria uma boa ideia ..

... e é um código público: provavelmente não . Você pode considerar o cache seletivamente, como no meu exemplo acima, em código público, mas geralmente é melhor se você deixar essas decisões para os implementadores.

... e é um código privado: muito provavelmente sim . Mas mesmo para o código privado, armazenar em cache seletivamente ainda é uma coisa boa, por exemplo, para depuração.

Lembre-se, de qualquer maneira, que wp_cache_*funções podem fornecer acesso ao cache sem o risco de poluir o banco de dados.

Devo usar a API transitória para armazenar em cache a matriz $ related_posts ou a cadeia $ html_output?

Depende de muitas coisas. Qual é o tamanho da corda? Qual cache externo você está usando? Se você estiver indo para cache de postagens, armazenar uma ID como matriz pode ser uma boa idéia, consultar um número decente de postagens por sua ID é bastante rápido.

Notas Finais

API transitória é provavelmente uma das melhores coisas do WordPress. Graças aos plugins que você pode encontrar para qualquer tipo de sistema de cache, torna-se uma API simples e estúpida para um grande número de software que pode funcionar sob o capô.

Fora do WordPress, é muito difícil encontrar essa abstração que funciona imediatamente com um monte de sistemas de cache diferentes e permite que você alterne de um sistema para outro sem nenhum esforço.

Você raramente pode me ouvir dizendo que o WordPress é melhor do que outras coisas modernas, mas a API transitória é uma das poucas coisas que sinto falta quando não trabalho com o WordPress.

Certamente o cache é difícil, não resolve problemas de código e não é uma bala de prata, mas é algo que você precisa para criar um site de alto tráfego que funcione.

A idéia do WordPress de usar uma tabela MySQL sub-otimizada para fazer cache é bastante insana, mas não é melhor manter-se longe do cache apenas porque o WordPress, por padrão, faz isso.

Você só precisa entender como as coisas funcionam e depois fazer sua escolha.

gmazzap
fonte
2

As respostas anteriores já destacaram o obrigatório " Depende ", com o qual concordo plenamente.

Gostaria de acrescentar uma recomendação, com base em como " suponho " que isso seria melhor feito no cenário que você está descrevendo acima.

Eu não usaria Transients nesse caso, mas sim o Post Meta , por causa de uma vantagem que o último possui: Control .

Como você precisa armazenar dados em cache por postagem, a quantidade de dados que você armazenará em cache depende do número de postagens e aumentará com o tempo. Depois de ultrapassar um certo número de postagens, você pode atingir os limites de memória que seu cache de objeto pode usar e ele começará a apagar os dados armazenados em cache anteriormente da memória antes de expirar. Isso pode levar a uma situação em que você tem um grande fluxo de visitantes, onde cada visitante aciona o "SQL excessivamente complexo" a cada solicitação de página e seu site fica completamente atolado.

Se você armazenar em cache os dados em seu Post Meta, poderá não apenas controlar como eles são armazenados e recuperados, mas também controlar exatamente como eles são atualizados. Você adicionaria um trabalho cron para isso, que é executado apenas em períodos em que há menos ou nenhum tráfego no site. Portanto, a "consulta lenta" nunca é encontrada por usuários reais do site e você pode até pré-carregá-la, para que o trabalho já esteja concluído quando o primeiro visitante chegar.

Lembre-se de que todo o armazenamento em cache é uma troca! É por isso que a resposta usual é "Depende". e por que não há "santo grail cache".

Alain Schlesser
fonte