main content
< Volver a blog sobre aplicaciones móviles

Cómo optimizar el rendimiento y velocidad de carga de tu sitio Drupal con estrategias de caché avanzado y CDN

Cómo optimizar el rendimiento y velocidad de carga de tu sitio Drupal con estrategias de caché avanzado y CDN

Un Drupal sin tocar puede tardar entre 3 y 8 segundos en cargar. He visto servidores caerse bajo carga porque nadie configuró correctamente la caché de página. Con el stack correcto, ese mismo sitio sirve respuestas en menos de 500 ms. Esa diferencia la notan Google (Core Web Vitals como factor de ranking desde 2021), tu tasa de rebote y tus conversiones.

Este artículo recorre las capas de caché de Drupal 10 y Drupal 11: desde Internal Page Cache hasta BigPipe, pasando por Varnish, Redis y la integración con CDN. Sin rodeos.

Cómo funciona el sistema de caché nativo de Drupal

Drupal implementa caché por capas. Bien configurado, reduce drásticamente la carga del servidor y los tiempos de respuesta. Cada capa tiene una función específica y se complementa con las demás. Si saltas una capa, pagas el precio en TTFB.

Internal Page Cache: la primera línea

El módulo Internal Page Cache (incluido en el núcleo) almacena el HTML completo de cada página para usuarios anónimos. Petición entrante → Drupal comprueba si hay versión cacheada → la sirve directo, sin renderizado, sin consultas SQL, sin procesamiento de temas.

La invalidación es granular gracias al sistema de cache tags. Editas el nodo 42 → solo se purgan las páginas que lo incluyen. No se borra todo el sitio. Eso es lo que diferencia a Drupal de CMS más simples: invalidación quirúrgica, no por escopeta.

Para activarlo: /admin/modules. El tiempo máximo de caché va en /admin/config/development/performance ("Browser and proxy cache maximum age"). Un valor razonable: 3600 segundos. Si tu contenido cambia poco, sube a 86400. Mide antes de decidir.

Dynamic Page Cache: usuarios autenticados

Internal Page Cache no sirve para usuarios autenticados — cada sesión tiene contenido personalizado. Aquí entra Dynamic Page Cache: cachea los fragmentos comunes de la página y solo regenera los personalizados.

Funciona con cache contexts. Cada bloque declara qué varía: user, user.roles, session, url.query_args. El sistema decide qué sirve desde warm cache y qué recalcula. Sin declarar los contextos correctamente, el sistema no puede optimizar. Tu código debe ser explícito al respecto.

Cache tags, contexts y max-age: la tríada de metadatos

Todo elemento renderizable en Drupal (nodos, bloques, vistas, menús) declara tres tipos de metadatos:

  • Cache tags: identifican qué datos afectan al elemento. Un bloque con los últimos 5 artículos tiene tags node_list y node:42. Al editar el nodo 42, se invalidan todos los elementos con ese tag.
  • Cache contexts: definen las variaciones. Diferente por idioma → languages:language_interface. Diferente por rol → user.roles.
  • Cache max-age: tiempo en segundos antes de expirar. Cache::PERMANENT significa solo invalidación por tags, nunca por tiempo.

Alerta: un módulo que declare max-age: 0 en un bloque fuerza la regeneración completa en cada petición. Anula toda la caché de la página. He visto sitios con 2 segundos de tiempo de respuesta por culpa de un único bloque mal declarado. Audita tus cache headers antes de hacer otra cosa.

Varnish como reverse proxy de caché

Varnish se coloca delante de Drupal e intercepta las peticiones antes de que lleguen a Apache o Nginx. Internal Page Cache sigue pasando por el stack PHP. Varnish no. Responde directamente desde memoria.

Configuración básica de Varnish con Drupal

El módulo Varnish Purge conecta el sistema de cache tags de Drupal con Varnish. Al cambiar contenido, Drupal envía una petición PURGE a Varnish con los tags afectados. Solo se invalidan las páginas correspondientes. Nada más.

La configuración requiere: Varnish 6.x o 7.x en el servidor, VCL configurado para manejar la cabecera X-Drupal-Cache-Tags, y los módulos Purge, Purge Drush, Purge Queuer (coretags) y Varnish Purger. El purger apunta a la IP y puerto de Varnish desde /admin/config/development/performance/purge.

Un punto crítico que se ignora con frecuencia: el cache stampede. Si Varnish expira un objeto popular y llegan 500 peticiones simultáneas antes de que esté warm de nuevo, tu servidor PHP se dobla bajo la carga. Configura grace period en el VCL para servir el objeto expirado mientras se regenera. Ese detalle solo se aprende habiéndolo sufrido.

Impacto medible de Varnish

Páginas cacheadas: 5-20 ms de tiempo de respuesta, frente a 200-800 ms sin Varnish. Capacidad concurrente: de 50-200 peticiones típicas en PHP a miles por segundo desde memoria. Con buen ratio de contenido estático, hit rate del 85-95%. El 5-15% restante llega a Drupal. Varnish absorbe el resto.

Redis y Memcached: caché de backend en memoria

Por defecto, Drupal almacena su caché interna en tablas cache_* de la base de datos. En sitios con tráfico medio-alto, eso es un cuello de botella directo: cada lectura de caché genera una consulta SQL que compite con las consultas de contenido. He visto bases de datos MySQL saturadas solo por operaciones de caché. Inaceptable.

Redis como almacén de caché

Redis sustituye la base de datos como backend de caché mediante el módulo Redis. Tres líneas en settings.php:

$settings['redis.connection']['host'] = '127.0.0.1';
$settings['redis.connection']['port'] = '6379';
$settings['cache']['default'] = 'cache.backend.redis';

Resultado: lecturas de caché en microsegundos en lugar de milisegundos. Tu base de datos deja de procesar tráfico de caché y puede dedicarse a lo que importa.

Dimensionamiento de memoria

Un Drupal típico consume entre 256 MB y 1 GB en Redis. Configura maxmemory con política de evicción allkeys-lru — la recomendada para Drupal. Sin ese límite, Redis puede agotar la RAM del servidor. Monitoriza con redis-cli info memory. No lo configures una vez y te olvides.

BigPipe: percepción de velocidad para contenido dinámico

BigPipe es módulo del núcleo desde Drupal 8, inspirado en la técnica de Facebook. El objetivo: enviar al navegador las partes estáticas de la página de inmediato, mientras las partes dinámicas se procesan en segundo plano.

Cómo funciona BigPipe en la práctica

Usuario autenticado solicita una página → Drupal identifica los elementos no cacheables (bloques personalizados, formularios con tokens CSRF, contenido de usuario) → envía el HTML con placeholders → el navegador renderiza el contenido estático al instante → Drupal inyecta los fragmentos dinámicos a medida que los procesa.

El usuario percibe que la página carga en 200-400 ms aunque el contenido dinámico tarde 1-2 segundos. Eso impacta directamente en LCP y FCP de Core Web Vitals. Son métricas reales, no percepción subjetiva.

BigPipe viene en el núcleo. Se activa desde /admin/modules. Sin configuración adicional. Funciona con cualquier tema y módulo que siga las buenas prácticas de la render API. Si tus módulos custom no lo hacen, ese es tu problema, no de BigPipe.

CDN: distribuir contenido globalmente

Un CDN replica archivos estáticos (CSS, JavaScript, imágenes, fuentes) en servidores distribuidos geográficamente. Un usuario en Buenos Aires recibe los archivos desde Sudamérica, no desde un servidor en Europa con 200 ms de latencia base.

Módulo CDN de Drupal

El módulo CDN reescribe las URLs de los archivos estáticos para que apunten al dominio del CDN. Configuración básica en settings.php:

$config['cdn.settings']['mapping']['domain'] = 'cdn.ejemplo.com';
$config['cdn.settings']['mapping']['conditions']['extensions'] = [
  'css', 'js', 'png', 'jpg', 'jpeg', 'gif', 'svg', 'woff2', 'woff'
];

Proveedores y configuración

Los CDN más utilizados con Drupal: Cloudflare, Fastly, AWS CloudFront y KeyCDN. Fastly merece mención especial — actúa como CDN y como Varnish en la nube. Drupal.org lo usa para su propia infraestructura. No es marketing: es una decisión técnica respaldada por carga real.

La configuración del CDN debe incluir: cabeceras Cache-Control con tiempos largos para archivos estáticos (1 año para archivos con hash), compresión Brotli o Gzip, y HTTP/2 o HTTP/3 para multiplexar peticiones. Drupal añade query string con timestamp a CSS/JS (styles.css?v=1685520000) para forzar descarga de nuevas versiones tras cada despliegue. Ese mecanismo ya está. Aprovéchalo.

Optimización de frontend: CSS, JavaScript e imágenes

La caché y el CDN aceleran la entrega. Pero si lo que entregas es pesado, el rendimiento sigue siendo pobre. Las dos cosas importan.

Agregación y minificación de CSS/JS

Drupal incluye agregación nativa en /admin/config/development/performance: "Aggregate CSS files" y "Aggregate JavaScript files". Activar ambas reduce el número de peticiones HTTP combinando múltiples archivos en uno.

Para más control: módulo Advanced CSS/JS Aggregation (AdvAgg). Minificación avanzada, eliminación de CSS no utilizado, carga diferida de JavaScript, control granular de orden de carga. En Drupal 10/11 sigue siendo la referencia para optimización de assets.

Configuraciones recomendadas de AdvAgg: minificación de CSS y JS, compresión Brotli, diferir JavaScript no crítico, eliminar CSS render-blocking para mejorar FCP. Sin esto, tu FCP sufre aunque tengas Varnish delante.

Optimización de imágenes

Drupal gestiona estilos de imagen que redimensionan y comprimen automáticamente. La configuración que no deberías saltarte:

  1. Definir estilos de imagen para cada contexto (thumbnail, listado, detalle, hero) en /admin/config/media/image-styles.
  2. Activar WebP: módulo WebP o configuración nativa de Drupal 10.1+. Reduce el peso entre 25% y 35% respecto a JPEG. Misma calidad visual. Menos bytes. Sin excusas.
  3. Lazy loading: Drupal 10/11 añade loading="lazy" automáticamente a imágenes fuera del viewport inicial. No descargues lo que el usuario no puede ver.
  4. Responsive images: módulo Responsive Image del núcleo genera etiquetas <picture> con múltiples fuentes según el tamaño de pantalla. Un móvil no tiene que descargar una imagen de 2000 px de ancho.

Monitorización y diagnóstico de rendimiento

Optimizar sin medir es trabajar a ciegas. Sin excepciones.

Herramientas integradas

  • Webprofiler (parte de Devel): tiempo de respuesta, consultas SQL, cache hits/misses y servicios invocados por página. Imprescindible en desarrollo.
  • Syslog / Dblog: registran errores y advertencias que señalan consultas lentas, errores de caché, timeouts.
  • Drush: drush cache:rebuild regenera toda la caché; drush cache:get inspecciona entradas específicas.

Herramientas externas

  • Google PageSpeed Insights: puntuaciones de Core Web Vitals (LCP, INP, CLS) con recomendaciones específicas.
  • GTmetrix: cascada de carga (waterfall) que identifica qué recursos tardan más.
  • New Relic o Blackfire: perfiladores que exponen funciones PHP lentas y consultas costosas. Si tienes tráfico real, necesitas uno de los dos.

Los objetivos para un Drupal bien configurado: TTFB inferior a 200 ms, FCP por debajo de 1 segundo, LCP bajo 2.5 segundos, CLS menor a 0.1, peso total de página bajo 1.5 MB. Revisa tus métricas contra estos números. Si no cumples alguno, hay un cuello de botella que resolver.

De un Drupal lento a un Drupal que compite en velocidad

No es una acción puntual. Es un stack de decisiones que se refuerzan: Internal Page Cache y Dynamic Page Cache como base. Varnish para multiplicar la capacidad de respuesta. Redis para liberar la base de datos. BigPipe para mejorar la percepción de velocidad. CDN para acercar los archivos al usuario. Optimización de assets para reducir el peso de lo transferido.

Cada capa suma. Pero es la combinación lo que transforma un Drupal de 4 segundos en uno que responde en menos de medio segundo. La secuencia importa: mide primero, identifica tus cuellos de botella concretos, aplica por capas en el orden correcto.

Si quieres saber exactamente dónde pierde rendimiento tu sitio Drupal, pide una auditoría técnica a nuestro equipo y te decimos qué ajustar y en qué orden.

Contacta con nosotros
Fila 1