¿Debo usar la API transitoria para almacenar cadenas u objetos HTML?

18

Supongamos que hay un complemento que muestra 20 publicaciones relacionadas (para cada publicación) con una consulta muy compleja. Y luego, utilizando los datos de esta consulta, construye un diseño HTML complejo. Además, debe tener en cuenta que el complemento es público y se puede instalar en cualquier servidor con cualquier configuración.

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

Así que mis preguntas son:

  • ¿Cuál es la forma más segura y correcta de almacenar en caché tales datos?
  • ¿Debo usar Transient API para almacenar en caché $related_posts array o $html_output string? Si almacenaré en caché $html_ouput cadena, ¿alcanzará algún límite de tamaño máximo? ¿Tal vez debería gzip, antes de guardar?
  • ¿Debo usar Transient API en absoluto aquí?
pregunta Marvin3 23.01.2016 - 17:22

3 respuestas

18
  

¿Debo usar Transient API en absoluto aquí?

No.

En un stock, los transitorios de instalación de WordPress se almacenan en la tabla wp_options y solo se limpian durante las actualizaciones principales. Supongamos que tiene 50,000 publicaciones, eso es 50,000 filas adicionales en la tabla de opciones. Obviamente, están configurados en carga automática = no, por lo que no consumirá toda la memoria, pero hay otra advertencia.

El campo de carga automática en la tabla de opciones no tiene un índice, lo que significa que la llamada a wp_load_alloptions() realizará una exploración completa de la tabla. Cuantas más filas tenga, más tiempo tomará. Cuanto más a menudo escribas en la tabla de opciones, menos eficientes son las cachés internas de MySQL.

Si los datos almacenados en la memoria caché están directamente relacionados con una publicación, es mejor que los almacenes en el metadatos de la publicación. Esto también le ahorrará una consulta cada vez que necesite mostrar el contenido almacenado en caché, porque los cachés de metadatos posteriores a la publicación (por lo general) están cebados durante la recuperación de publicaciones en WP_Query.

Su estructura de datos para el valor meta puede variar, puede tener una marca de tiempo y realizar una consulta costosa si el valor almacenado en caché está desactualizado, de manera muy similar a como se comportaría un transitorio.

Otro aspecto importante a tener en cuenta es que los transitorios de WordPress pueden ser volátiles en entornos con caché de objetos persistente. Esto significa que si almacena sus datos almacenados en caché durante 24 horas en un transitorio, no hay absolutamente ninguna garantía de que estará disponible en 23 horas, 12 o incluso 5 minutos. El backend del caché de objetos para muchas instalaciones es un almacén de valor-clave en la memoria como Redis o Memcached, y si no hay suficiente memoria asignada para adaptarse a objetos más nuevos, se desalojarán los elementos más antiguos. Esta es una gran victoria para el enfoque de almacenamiento meta.

La invalidación también puede ser más inteligente, es decir, ¿por qué está invalidando las cachés de publicaciones relacionadas en X horas? ¿Es porque algún contenido ha cambiado? ¿Se ha agregado una nueva publicación? ¿Se ha asignado una nueva etiqueta? Dependiendo de su "consulta compleja y grande" puede elegir invalidar SOLAMENTE si algo sucedió que alterará los resultados de su consulta.

  

¿Debo usar Transient API para almacenar en caché $ related_posts array o $ html_output string? Si almacenaré en caché la cadena $ html_ouput, ¿alcanzará algún límite de tamaño máximo? ¿Tal vez debería gzip, antes de guardar?

Depende mucho del tamaño de su cadena, ya que esos serán los datos que fluirán entre PHP, MySQL, etc. Deberá esforzarse mucho para alcanzar los límites de MySQL, pero por ejemplo, Memcached predeterminado el límite del objeto es de solo 1 mb.

¿Cuánto tiempo toma realmente su "lógica de representación de diseño complejo"? Ejecutarlo a través de un perfilador para averiguarlo. Es probable que sea muy rápido y nunca se convierta en un cuello de botella.

Si ese es el caso, sugeriría almacenar en caché las ID de las publicaciones. No los objetos WP_Post, porque contendrán el contenido completo de la publicación, sino solo una matriz de ID de publicación. Luego solo use un WP_Query con un post__in , lo que resultará en una consulta de MySQL muy rápida por clave principal.

Dicho esto, si los datos necesarios para cada elemento son bastante simples, tal vez el título, la url de las miniaturas y el enlace permanente, entonces puede almacenar solo esos tres, sin la sobrecarga de un viaje de ida y vuelta a MySQL, y sin la sobrecarga del almacenamiento en caché cadenas HTML muy largas.

Vaya, muchas palabras, espero que ayuden.

    
respondido por el kovshenin 25.01.2016 - 15:18
12

No todos los códigos WP son códigos públicos

Si vas a lanzar algo público, entonces todas las cosas kovshenin Dicho es perfectamente válido.

Las cosas son diferentes si va a escribir un código privado para usted o para su empresa.

La caché de objetos externos es un gran beneficio, en cualquier caso

Establecer un caché externo de objetos persistentes es muy recomendable , cuando puedes.

Todas las cosas que se dicen en la respuesta de kovshenin sobre los transitorios y MySQL son muy ciertas, y considerando que WP en sí y un montón de complementos hacen uso de la caché de objetos ... entonces la mejora de rendimiento que obtienes, vale la pena (pequeña) esfuerzo para configurar un sistema de caché moderno como Redis o Memcached.

Es posible que los valores en caché no estén allí: eso está bien

Además, sí, una caché de objetos externa es no confiable. Nunca debes confiar en el hecho de que un transitorio está ahí. Debe asegurarse de que funcione si el almacenamiento en caché no está donde debería estar.

El caché no es almacenamiento, el caché es caché.

Usar caché selectivamente

Vea este ejemplo:

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

Al usar un código como este, en su sitio privado, el rendimiento del sitio puede mejorar mucho , especialmente si tiene muchos usuarios.

Tenga en cuenta que:

  • De forma predeterminada, el caché no se usa cuando la depuración está activada, por lo que es de esperar que en su entorno de desarrollo. Créeme, el caché puede hacer que la depuración sea un infierno
  • Por defecto, el caché tampoco se usa cuando WP no está configurado para usar un caché de objetos externo. Significa que no existe todo el problema relacionado con MySQL, porque no usas transitorios cuando usan MySQL. Una alternativa probablemente más fácil sería usar wp_cache_* functions , por lo que si no se configura un caché externo, entonces el caché sucede en la memoria, y la base de datos nunca está involucrada.
  • El uso de la memoria caché se puede filtrar, para manejar algunos casos de borde que puede encontrar

Sin escala web si no hay caché

No debes tratar de resolver problemas de velocidad con el caché. Si tiene problemas de velocidad, debería volver a pensar que codifica.

Pero para escalar un sitio web a escala web, el caché es muy necesario .

Y muchas veces (pero no siempre), el caché sensible al contexto es mucho más flexible y adecuado que el caché de página completa agresivo.

Sus preguntas:

  

¿Debo usar Transient API en absoluto aquí?

Depende .

¿Su código consume muchos recursos? Si no, tal vez no hay necesidad de caché. Como se ha dicho, no es solo una cuestión de velocidad. Si su código se ejecuta rápidamente pero requiere un montón de CPU y memoria para un par de usuarios ... ¿qué sucede cuando tiene 100 o 1000 usuarios simultáneos?

Si te das cuenta de que el caché sería una buena idea ...

... y es un código público: probablemente no . Puede considerar el almacenamiento en caché de forma selectiva, como en mi ejemplo anterior en el código público, pero generalmente es mejor si deja esas decisiones a los implementadores.

... y es un código privado: muy probablemente sí . Pero incluso para el código privado, almacenar en caché de forma selectiva sigue siendo algo bueno, por ejemplo, para la depuración.

Recuerde, de todos modos, que las funciones wp_cache_* pueden darle acceso a la memoria caché sin el riesgo de contaminar la base de datos.

  

¿Debo usar Transient API para almacenar en caché $ related_posts array, o $ html_output string?

Depende de muchas cosas. ¿Qué tan grandes son las cuerdas? ¿Qué caché externo estás usando? Si va a almacenar en caché las publicaciones, el almacenamiento de ID como matriz puede ser una buena idea, consultar un número decente de publicaciones por su ID es bastante rápido.

Notas finales

La API transitoria es probablemente una de las mejores cosas de WordPress. Gracias a los complementos que puede encontrar para cualquier tipo de sistemas de caché, se convierte en una API simple y estúpida para una gran cantidad de software que puede funcionar bajo el capó.

Fuera de WordPress, es muy difícil encontrar una abstracción que funcione de manera inmediata con un conjunto de diferentes sistemas de almacenamiento en caché, y que te permita cambiar de un sistema a otro sin ningún esfuerzo.

Raramente me escuchas decir que WordPress es mejor que otras cosas modernas, pero la API transitoria es una de las pocas cosas que echo de menos cuando no trabajo con WordPress.

Seguramente el caché es difícil, no resuelve los problemas de código y no es una bala de plata, pero es algo que necesitas para construir un sitio de alto tráfico que funcione.

La idea de WordPress de utilizar una tabla de MySQL poco optimizada para hacer caché es bastante insensata, pero no es mejor mantenerse alejado de la caché solo porque WordPress, de forma predeterminada, lo hace.

Solo necesitas entender cómo funcionan las cosas, luego haz tu elección.

    
respondido por el gmazzap 26.01.2016 - 21:28
2

Las respuestas anteriores ya han resaltado el obligatorio " Depende. ", con lo que estoy completamente de acuerdo.

Sin embargo, me gustaría agregar una recomendación, según cómo " supongo " esto se haría mejor en el escenario que se describe arriba.

No usaría Transients en ese caso, sino Post Meta , debido a una ventaja que esta última tiene: Control .

Como necesita almacenar en caché los datos por publicación, la cantidad de datos que almacenará en caché depende de la cantidad de publicaciones y aumentará con el tiempo. Una vez que supere un cierto número de publicaciones, puede llegar a los límites de la memoria que su caché de objetos puede usar, y comenzará a borrar los datos almacenados previamente en la memoria caché antes de que caduque. Esto podría llevar a una situación en la que tenga una gran afluencia de visitantes, donde cada visitante activará el "SQL excesivamente complejo" en cada solicitud de página, y su sitio quedará completamente bloqueado.

Si almacena en caché los datos en su Meta Meta, no solo puede controlar cómo se almacenan y recuperan, sino que también puede controlar exactamente cómo se actualizan. Agregaría un trabajo cron para esto que se ejecute solo en periodos de tiempo en los que hay menos o ningún tráfico al sitio. Por lo tanto, la "consulta lenta" nunca es encontrada por usuarios reales del sitio, e incluso puede precargarla, para que el trabajo ya esté hecho cuando llegue el primer visitante.

¡Tenga en cuenta que todo almacenamiento en caché es una compensación! Es por eso que la respuesta habitual es "depende". y por qué no hay un "santo grial escondido".

    
respondido por el Alain Schlesser 27.01.2016 - 12:10

Lea otras preguntas en las etiquetas