Rendimiento

Última actualización: 8 de junio de 2019

WordPress es un sistema estable pero que depende del rendimiento del sistema operativo, servidor web, PHP y base de datos para funcionar correctamente. Al ser un software ejecutado en el servidor, cada vez que un usuario llegue se ejecutará por completo.

Es por esto que se recomiendan algunas mejoras y cambios para la mejora del rendimiento de todo el sistema.

Caché

WordPress por defecto es 100% dinámico, lo que significa que cada vez que alguien accede se ha de generar todo por completo, lo que tiene un cálculo muy elevado. Algunos de estos elementos que pueden ralentizar los procesos son consultas a la base de datos, la propia ejecución de PHP, llamadas a API externas…

Es por esto que se recomienda cachear. Este proceso permite reutilizar resultados anteriormente calculados en varias ocasiones siguiendo una serie de reglas, lo que reduce el consumo de tareas repetitivas.

Normalmente la caché se renueva según pasa un periodo de tiempo predefinido, de forma que durante el tiempo en que la caché está activa los resultados se devuelve rápidamente, ya que se suelen recuperar del disco o de la memoria y no se han de calcular.

Existen muchas capas de caché, y en cada una de ellas se puede actuar de una manera distinta. WordPress, conjuntamente con configuraciones del sistema y con plugins, es capaz de utilizarlas. En general se suelen llamar en este orden:

  1. Caché del navegador, caché local o Web App Manifest
  2. CDN (Content Delivery Network)
  3. Caché de página, en servidor web o proxy
  4. Caché de página, estática o por PHP
  5. Opcode caché
  6. Caché de objetos
  7. Caché de fragmentos
  8. Transient API
  9. Caché de base de datos
  10. Caché de ficheros en disco

Cada sistema de caché funciona de una forma diferente, puede estar en el mismo servidor o en varios, puede estar en el mismo dominio o en distintos, en incluso puede ser una cadena de llamadas. Además, cada sistema de caché puede requerir ciertas configuraciones que no están habilitadas por defecto, como puede ser un almacenamiento distinto, memoria RAM, conexiones físicas distintas, tiempos de latencia… esto significa que la optimización de la caché, en muchos casos, también dependerá de la configuración de las máquinas que las gestionan. Por ejemplo, el acceso a la memoria RAM es más rápida que el acceso a un disco SSD que es más rápida que el acceso a un disco HDD.

Caché del navegador

Los navegadores web que usamos para visitar los sitios permiten almacenar información que se puede necesitar en varias ocasiones a lo largo de la navegación por el sitio. Por eso es muy probable que la primera visita a un sitio web vaya más lenta, pero posteriormente la velocidad de carga aumente, ya que parte de la información queda almacenada.

Un ejemplo sería el de añadir al fichero .htaccess (en el caso de usar un servidor web Apache HTTPD) con el siguiente contenido, que fuerza a almacenar los distintos tipos los segundos indicados:

<IfModule mod_expires.c>
  ExpiresActive on
  #Varios
  ExpiresByType application/pdf A2592000
  ExpiresByType image/x-icon A2592000
  ExpiresByType image/vnd.microsoft.icon A2592000
  ExpiresByType image/svg+xml A2592000
  #Imagenes
  ExpiresByType image/jpg A2592000
  ExpiresByType image/jpeg A2592000
  ExpiresByType image/png A2592000
  ExpiresByType image/gif A2592000
  ExpiresByType image/webp A2592000
  #Media
  ExpiresByType video/ogg A2592000
  ExpiresByType audio/ogg A2592000
  ExpiresByType video/mp4 A2592000
  ExpiresByType video/webm A2592000
  #CSS/JS
  ExpiresByType text/css A2592000
  ExpiresByType text/javascript A2592000
  ExpiresByType application/javascript A2592000
  ExpiresByType application/x-javascript A2592000
  #Fuentes
  ExpiresByType application/x-font-ttf A2592000
  ExpiresByType application/x-font-woff A2592000
  ExpiresByType application/font-woff A2592000
  ExpiresByType application/font-woff2 A2592000
  ExpiresByType application/vnd.ms-fontobject A2592000
  ExpiresByType font/ttf A2592000
  ExpiresByType font/woff A2592000
  ExpiresByType font/woff2 A2592000
</IfModule>

CDN – Content Distribution Network

Las redes de distribución de contenidos están pensadas para reducir la latencia, los tiempos de respuesta, a la hora de servir contenidos en distintas zonas geográficas. Si tu proyecto WordPress es internacional, sin duda es una buena opción para, al menos, contenidos estáticos como JavaScript o CSS ademas de imágenes y contenidos media. Si tu proyecto es bastante local, lo mejor es disponer de una infraestructura conectada en ese país.

Además, por lo general, los CDN también actual como una capa de caché, ya que al disponer de los contenidos y solo servir los estáticos, no han de hacer cálculos y están optimizados para servirse lo más rápido posible. En caso de trabajar con varias capas de caché, has de asegurarte que se purga en todos los niveles, porque puede hacerse una limpieza en un nivel, pero no en otro, y seguir sirviéndose algo que no ha sido invalidado.

Caché de página

Cuando se hace una solicitud de una página, por ejemplo la principal de un blog, se ejecutan varios procesos en PHP, se hace el cálculo para la recuperación de los contenidos en la base de datos, se calculan configuraciones personalizadas y finalmente se pinta por pantalla. En muchas ocasiones, los contenidos entre una petición y otra no ha cambiado por lo que ¿por qué no mostrar la información calculada en la primera de esas dos ocasiones?

La mejor forma de realizar copias de caché suele ser poner un sistema entre el usuario y el servidor web. De esa forma se solicita la información, se sirve, y posteriormente se verifican los cambios o se deja igual hasta que se invalida la información. Esta capa intermedia puede ser un proxy, habitualmente gestionado por herramientas como nginx (reverse proxy) o Varnish Cache que almacenan una copia de la solicitud y la sirven hasta que el sistema queda invalidado de forma manual o automáticamente cuando llega al tiempo de expiración. Estos sistemas suelen almacenar una copia en memoria, de forma que se sirve mucho más rápido que de cualquier otro sistema.

En caso de no disponer de un sistema de este estilo, siempre cabe la posibilidad de realizar esa copia en el propio servidor web; no es la opción más rápida pero siempre será mejor que tener que calcular todo. La mayoría de plugins de caché que hay para WordPress utilizan este sistema.

En el caso de las imágenes, scripts, hojas de estilo y similares, lo mejor es servirlos directamente si existen y no pasar por sistemas de procesado como PHP.

En caso de usar cualquiera de estos sistemas, recuerda que siempre es útil disponer de un sistema que vaya invalidando la información, por ejemplo, cuando se publique nueva en el sitio. Lo mejor es que se pueda usar un sistema que solo elimine aquellas páginas que se vean afectadas y no todo el sitio.

Recuerda también que habrá páginas que no se deben cachear nunca, ya que son distintas para cada usuario, como por ejemplo la página del carrito de la compra de un comercio electrónico, o el proceso de pago y posteriores.

Otro elemento a tener muy presente a la hora de configurar las caché es el tiempo habitual en el que se guardará la información hasta que quede invalidada. Por ejemplo, una web corporativa podría cachear la información 1 semana, un blog en el que se publica con poca frecuencia, con una vez al día sería suficiente pero, en cambio, un comercio electrónico tal vez solo 1 hora.

Algunos plugins interesantes para gestionar la caché pueden ser: WP Super Cache, WP Fastest Cache, W3 Total Cache, Simple Cache.

En caso de trabajar con sistemas como nginx o LiteSpeed tienes estos: LiteSpeed Cache, Nginx Cache.

Opcode caché

Cada vez que llega una petición a tu servidor web, PHP ha de ejecutarse y calcular todo, pero PHP permite un sistema interno de caché de operaciones, lo que significa que se almacena una copia de cada ejecución en memoria o en disco. Si está activo y se ejecuta de nuevo la misma operación, el sistema aprovechará este sistema para devolver el cálculo mucho más rápido, ya que no ha de calcular todo por completo.

Si tu proveedor de alojamiento lo tiene activo y configurado, puedes hacer uso de él, pero siempre teniendo en cuenta que necesitarás un plugin para hacer la invalidación de los contenidos cuando sea necesario.

Algunos plugins que pueden ser útiles: OPcache Reset, WP OPcache, OPCache Scripts.

Caché de objetos

Hace muchas versiones de WordPress que tenemos la posibilidad de almacenar algunos elementos en la llamada caché de objetos. Estos objetos principalmente suelen ser elementos pre calculados asociados a consultas de búsqueda.

Gracias a este sistema y con la ayuda de servidores de almacenamiento externos como memcached o Redis podemos almacenar los datos calculados en unos sistemas pensados para una lectura muy rápida sin tener que almacenarlos en la base de datos. De esta forma, el sistema no tendrá que volver a ejecutar los cálculos sino que serán leídos directamente de un almacenamiento.

Lo interesante de este sistema es que no cachea toda la página calculada, sino partes de ella, lo que hace que en páginas que no se pueden cachear por completo, sí que lo hagan ciertas partes que no tienen porqué cambiar.

Algunos plugins que pueden ser útiles: Redis Object Cache, WP Redis, WP Memcached Manager.

Caché de fragmentos

Este tipo de caché permite disponer de caché por partes dentro del conjunto de una misma página. El sistema más conocido es el ESI (Edge Side Includes) y que, con sistemas externos que lo soporta, permitirían disponer de varias partes cacheadas y fusionar antes de ofrecer al cliente final.

Con este sistema, por ejemplo, una página de una tienda se podría cachear por partes, pudiendo tener una parte común y otras partes separadas, como por ejemplo el carrito que variaría según cada usuario y solo cambiaría si se añade algo en él.

WordPress por defecto no incorpora este sistema, aunque sí que se puede gestionar de forma parcial con sistemas como LiteSpeed Cache o Varnish Cache.

PHP

Sin duda el rendimiento de PHP es básico para el correcto funcionamiento de WordPress, ya que la mayoría del sistema depende de ello. Es por esto que la configuración óptima de PHP en tu alojamiento es imprescindible. PHP es un lenguaje interpretado que se ejecuta en el servidor, por lo tanto, el peso de la optimización se encuentra ahí.

Versión de PHP

Sin duda para el buen funcionamiento de WordPress deberíamos usar PHP 7.x, actualmente recomendable PHP 7.2+ o PHP 7.3+. Es conocido que las versiones anteriores a PHP 7.x (es decir, PHP 5.6 y anteriores) tienen un rendimiento un 30% menor que las versiones actuales. Además, en PHP 7.1 se hizo un cambio importante en lo que respecta a la encriptación, por lo que se recomienda usar al menos esa versión.

Has de tener también presente que la versión de PHP ha ir en correlación con la versión de WordPress que tengas. Versiones muy antiguas de WordPress ahora no funcionarían con las más modernas, por lo que se recomienda actualizar todo de forma paralela en la medida de lo posible.

También has de tener muy presente los themes y plugins en uso. Aunque WordPress 5.0 da soporte a versiones de PHP 5.2 hasta PHP 7.3, los plugins no suelen dar soporte a todas las versiones, por lo que mantener una versión poco actualizada puede significar que plugins muy conocidos y utilizados no funcionen correctamente.

A partir de WordPress 5.1 haya un control más exhaustivo sobre qué versiones de PHP se pueden usar, y los desarrolladores informarán de ello, de forma que se harán recomendaciones sobre el posible mal funcionamiento de alguna extensión del núcleo.

A partir de la versión de WordPress 5.2, se reduce el número de versiones compatibles y se da soporte de PHP 5.6 hasta PHP 7.3.

Configuración

PHP suele configurarse principalmente según su fichero de configuración php.ini que es leído según su ejecución. Además, se suele instalar e integrar con el servidor web en sus versiones CGI/FastCGI o en su modo PHP-FPM.

En caso de disponer de un sitio web de alto tráfico, quizá te interese el sistema de PHP-FPM.

Tiempo de espera (timeouts)

Los tiempos de espera de PHP han de ir en consonancia con los del servidor web, por lo que esta configuración ha de ir ligeramente acorde entre ambos sistemas. Por ejemplo, no tiene sentido configurar PHP para que tenga un tiempo de 120 segundos si el servidor web tiene uno de 30 segundos.

Cada proceso puede llevar un tiempo de espera distinto, por ejemplo dependiendo de la carga del servidor, y es por esto que estos tiempos de espera se configuran, para que esos procesos largos no dejen bloqueado otros procesos hasta saturar el sistema. Es por esto que la elección del tiempo de espera deberá ir acorde a la carga del servidor y la buena ejecución de los procesos.

El timeout PHP primario puede ser establecido con la directiva max_execution_time en php.ini. Este limita la ejecución de código y no las llamadas a la biblioteca del sistema o las consultas SQL (excepto en Windows donde sí lo hace).

El tiempo máximo permitido para la transferencia de datos desde el servidor web a PHP se especifica con la directiva max_input_time en php.ini. Normalmente se utiliza para limitar el tiempo permitido para subir archivos. Es importante tener presente que la cantidad de tiempo es diferente de max_execution_time y define la cantidad de tiempo entre el momento en que el servidor web llama a PHP y el inicio de la ejecución.

Límite de memoria

El límite de memoria utilizado por PHP se puede configurar en las directivas del php.ini. Aún así, WordPress permite desde el fichero de configuración wp-config.php establecer los límites. De esta forma si los del servidor son mayores se ejecutarán esos, pero si los que establece WordPress son mayores, se usaran esos.

define( 'WP_MEMORY_LIMIT', '128M' );

Esta opción declara la cantidad de memoria que WordPress debe solicitar para renderizar el frontal (front-end) del sitio web.

define( 'WP_MAX_MEMORY_LIMIT', '256M' );

Como habitualmente el panel de administración (wp-admin) requiere más memoria, hay una configuración separada para la cantidad que se puede establecer para los usuarios que han iniciado sesión. Esto suele ser muy útil en la carga de imágenes (ya que tras la subida suelen ser procesadas). Puedes establecerlo por encima del límite del frontal para asegurar que su panel de administración tiene todos los recursos que necesita.

Subida de ficheros

Al subir archivos multimedia y otros contenidos a WordPress utilizando el panel de administración, WordPress utiliza PHP para procesar las subidas. La configuración de PHP incluye límites del tamaño de los ficheros que pueden ser cargados a través de PHP y en el tamaño de las peticiones que pueden ser enviadas al servidor web para su procesamiento. Estos tendrán que alinearse con los tiempos de espera del servidor.

El límite en el tamaño de las subidas de archivos individuales puede ser configurado usando upload_max_filesize en php.ini. Aunque no hay una cifra establecida, una recomendación que cumple la mayoría de los casos puede ser la de 32MB.

El límite en el tamaño total de una petición que puede ser enviada desde el servidor web a PHP para su procesamiento puede ser configurado usando la directiva post_max_size en php.ini. El valor para post_max_size debe ser mayor o igual que el valor para upload_max_filesize.

Hay que tener presente que post_max_size se aplica a cada petición PHP y no sólo a las subidas, por lo que puede ser importante tratar por separado si un sitio procesa una gran cantidad de otros datos en cada petición.

Programador de tareas (Crones)

Para el buen funcionamiento de WordPress se han de ejecutar una serie de tareas. Estas tareas no se ejecutan en primer plano, sino en segundo plano, por lo que de alguna manera se ha de lanzar un algo que los ejecute. Es por esto que cada vez que un usuario visita la página se lanza el sistema de WP-Cron (wp-cron.php).

Aunque este chequeo no suelen consumir muchos recursos, si un sitio web tiene mucho tráfico, se puede saturar el sistema. De la misma manera, si un sitio tiene poco tráfico, puede que estas tareas no se ejecuten con la frecuencia recomendada.

En estos casos, lo mejor es deshabilitar el sistema de crones mediante la configuración del wp-config.php.

define( 'DISABLE_WP_CRON', true );

En este caso, deberías plantear, por ejemplo, configurar en el propio servidor la ejecución del mismo de forma manual mediante el uso de WP-CLI. En este caso se configura su ejecución cada 5 minutos. A menos que tengas un sitio de alto tráfico o con requerimientos altos (como un comercio electrónico) debería ser suficiente cada 5 minutos, pero se puede reducir la ejecución a cada minuto.

*/5 * * * * WP_CLI_PHP=/usr/local/bin/php; SHELL=/bin/bash; /usr/local/bin/wp cron event run --due-now --path=/home/example.com/public_html/ >/dev/null 2>&1

En caso de no disponer de WP-CLI, siempre se puede hacer uso de la llamada directamente de forma pública, aunque es recomendable por seguridad limitar las llamadas a las IP que hagan las peticiones (la propia máquina o el servicio externo que haga las peticiones).

*/5 * * * * wget -q -O - https://example.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1

Un caso más extremo, y que requiere algo de conocimiento de programación en PHP y shell, podría ser el de crear un pequeño código en PHP que ejecute el cron en local, de forma que no se tenga que acceder de forma externa.

Para esto crearíamos un fichero PHP con el siguiente código (por ejemplo de nombre /home/example.com/run-wp-cron.php):

<?php
chdir('/home/example.com/public_html/'); // la ruta absoluta donde se encuentra WordPress
include('wp-cron.php');

Y que llamaríamos desde el cron con la siguiente consulta:

*/5 * * * * /usr/bin/php /home/example.com/run-wp-cron.php > /dev/null 2>&1

Existen muchas maneras de hacer las llamadas correspondientes a las tareas programadas, por lo que es muy recomendable que hables con tu proveedor de alojamiento web para que te recomiende la mejor manera.