Devo usar a API temporária para armazenar String HTML ou Object?

18

Vamos supor que exista um plug-in que exiba 20 publicações relacionadas (para cada postagem) com uma consulta muito complexa. E, em seguida, usando dados dessa consulta, ele cria um layout HTML complexo. Além disso, deve-se notar que o plugin é 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 esses dados?
  • Devo usar a API temporária para armazenar em cache $related_posts array ou $html_output string? Se eu armazenar em cache $html_ouput string, atingirá algum limite de tamanho máximo? Eu deveria gzip antes de salvar?
  • Devo usar a API transitória aqui?
por Marvin3 23.01.2016 / 17:22

3 respostas

18
  

Devo usar a API transitória em tudo aqui?

Não.

Em um estoque, os transientes 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, por isso não vai 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 para wp_load_alloptions() executará uma varredura completa da tabela. Quanto mais linhas você tiver, mais tempo levará. Quanto mais você escreve na tabela de opções, menos eficientes são os caches internos do MySQL.

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

Sua estrutura de dados para o valor meta pode variar, você pode ter um registro de data e hora e executar sua consulta cara se o valor em cache estiver desatualizado, da mesma forma que um transiente se comportaria.

Um outro pensamento importante a ter em mente é que os transientes do WordPress podem ser voláteis em ambientes com cache de objeto persistente. Isso significa que, se você armazenar seus dados em cache por 24 horas em um transiente, não há garantia de que eles estarão disponíveis em 23 horas, 12 ou até 5 minutos. O backend de cache de objetos para muitas instalações é um armazenamento de valor de chave na memória, como Redis ou Memcached, e se não houver memória alocada suficiente para ajustar-se a objetos mais novos, 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 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 APENAS se algo acontecer que altere os resultados da sua consulta.

  

Devo usar a API temporária para armazenar em cache a matriz $ related_posts ou a string $ html_output? Se eu armazenar em cache a string $ html_ouput, ela atingirá um limite de tamanho máximo? Eu deveria gzip antes de salvar?

Depende muito do tamanho da sua string, já que são os dados que vão fluir entre PHP, MySQL, etc. Você terá que se esforçar muito para alcançar os limites do MySQL, mas por exemplo o padrão do Memcached. o limite de objeto é de apenas 1 mb.

Por quanto tempo sua "lógica complexa de renderização de layout" demora? Execute-o através de um profiler para descobrir. As chances são de que é muito rápido nunca vai se tornar um gargalo.

Se esse for o caso, sugiro colocar em cache as IDs dos postagens. Não os objetos WP_Post, porque eles conterão o conteúdo completo da postagem, mas apenas uma matriz de IDs de postagem. Em seguida, use apenas WP_Query com post__in , o que 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 de miniatura e link permanente, você poderá armazenar apenas esses três, sem a sobrecarga de uma ida e volta extra para o MySQL e sem a sobrecarga de cache strings HTML muito longas.

Uau, isso é um monte de palavras, espero que ajude.

    
por kovshenin 25.01.2016 / 15:18
12

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

Se você vai lançar algo público, então todas as coisas kovshenin disse são perfeitamente válidos.

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

Cache de objeto externo é um grande benefício, em qualquer caso

Para definir um cache de objeto persistente externo é muito recomendado , quando puder.

Todas as coisas ditas na resposta do kovshenin sobre transientes e MySQL são verdadeiras, e considerando que o próprio WP e um monte de plugins fazem uso do cache de objetos ... então a melhoria de desempenho que você obteve, absolutamente vale a pena esforço para configurar um sistema de cache moderno como Redis ou Memcached.

Valores em cache podem não estar disponíveis: ótimo

Além disso, sim, um cache de objeto externo é não confiável. Você nunca deve confiar no fato de que um transiente está lá. Você precisa ter certeza de que funciona se o cache não estiver onde eles devem estar .

Cache não é armazenamento, cache é cache.

Use 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 este, em seu site privado, o desempenho do site pode melhorar muito , especialmente se você tiver muitos usuários.

Observe que:

  • Por padrão, o cache não é usado quando a depuração está ativada, portanto, esperamos que em seu ambiente de desenvolvimento. Acredite, cache pode fazer depurar 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 relacionado ao MySQL não existe, porque você não usa transientes quando eles usam o MySQL. Uma alternativa provavelmente mais fácil seria usar wp_cache_* functions , portanto, se nenhum cache externo for configurado, o cache acontecer na memória, e o banco de dados nunca está envolvido.
  • O uso do cache é filtrável, para lidar com alguns casos de borda 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, repita o código.

Mas para escalar um site na webscale, o cache é bastante obrigatório .

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

Suas perguntas:

  

Devo usar a API transitória em tudo aqui?

Depende .

Seu código consome muitos recursos? Se não, talvez não haja necessidade de cache. Como foi dito, não é apenas uma questão de velocidade. Se o seu código rodar rápido, mas requer um monte de CPU e memória para alguns usuários ... o que acontece quando você tem 100 ou 1.000 usuários simultâneos?

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

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

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

Lembre-se, de qualquer forma, que wp_cache_* funções podem lhe dar 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 string $ html_output?

Depende de muitas coisas. Quão grande é a string? Qual cache externo você está usando? Se você for fazer um cache de posts, o armazenamento de IDs como array pode ser uma boa ideia. Consultar um número decente de posts por seu ID é bastante rápido.

Notas Finais

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

Fora do WordPress, tal abstração que funciona de forma diferente com um monte de sistema de cache diferente, e permite que você mude de um sistema para outro sem nenhum esforço é muito difícil de encontrar.

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 é um marcador de prata, mas é algo que você precisa para criar um site de alto tráfego que funcione.

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

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

    
por gmazzap 26.01.2016 / 21:28
2

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

No entanto, gostaria de adicionar uma recomendação, com base em como "suponho que" isso seria melhor feito no cenário descrito acima.

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

Como você precisa armazenar os dados em cache por postagem, a quantidade de dados armazenados em cache depende do número de postagens e aumentará com o tempo. Uma vez que você ultrapasse um certo número de posts, você pode atingir os limites de memória que seu cache de objetos tem permissão para usar, e ele irá começar a apagar os dados previamente armazenados em cache da memória antes de expirar. Isso pode levar a uma situação em que você tem um grande afluxo de visitantes, onde cada visitante acionará o "SQL excessivamente complexo" em cada solicitação de página, e seu site ficará completamente atolado.

Se você armazenar os dados em cache no seu Post Meta, poderá controlar não apenas como eles são armazenados e recuperados, mas também poderá controlar exatamente como eles são atualizados. Você adicionaria uma tarefa cron para isso, que é executada apenas em períodos de tempo em que há menos tráfego para o 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 pronto quando o primeiro visitante chegar.

Tenha em mente que todo o armazenamento em cache é um compromisso! É por isso que a resposta usual é "depende". e por que não há "santo grail".

    
por Alain Schlesser 27.01.2016 / 12:10