Configuración de Varnish Cache

Varnish Cache es un potente acelerador HTTP y proxy inverso de caché que mejora dramáticamente el rendimiento de aplicaciones web al almacenar contenido en caché y servirlo a velocidades relámpago. Como una de las soluciones de caché más efectivas disponibles, Varnish puede manejar cientos de miles de solicitudes por segundo mientras reduce la carga del servidor backend hasta en un 90%. Esta guía completa le guiará a través de la instalación, configuración y optimización de Varnish Cache para potenciar su infraestructura web.

Ya sea que esté ejecutando un sitio web de noticias de alto tráfico, plataforma de comercio electrónico, sistema de gestión de contenidos o servicio API, implementar Varnish Cache puede transformar el perfil de rendimiento de su aplicación. Al almacenar inteligentemente en caché las respuestas HTTP y servirlas desde memoria, Varnish elimina el procesamiento redundante del backend y las consultas a la base de datos, ofreciendo mejoras de velocidad excepcionales que impactan directamente la experiencia del usuario y los rankings SEO.

Tabla de Contenidos

Prerrequisitos

Antes de instalar y configurar Varnish Cache, asegúrese de tener:

  • Sistema Operativo: Ubuntu 20.04/22.04, Debian 10/11, CentOS 8/Rocky Linux 8, o similar
  • Servidor Web Backend: Apache, Nginx o cualquier servidor HTTP ya configurado
  • RAM: Al menos 1GB RAM (se recomienda más para producción; Varnish almacena caché en memoria)
  • Acceso root o sudo: Requerido para instalación y configuración
  • Aplicación Backend: Aplicación web o sitio web en ejecución para almacenar en caché
  • Comprensión básica: Protocolo HTTP, conceptos de caché y administración de servidores web
  • Respaldo: Respaldo actual de la configuración de su servidor web

Varnish opera como un proxy inverso de caché, situándose entre clientes y su servidor web backend, por lo que asegúrese de que su backend esté correctamente configurado y en ejecución antes de proceder.

Entendiendo Varnish Cache

¿Qué es Varnish Cache?

Varnish Cache es un acelerador HTTP y proxy inverso de caché diseñado para sitios web dinámicos con mucho contenido y APIs. A diferencia de los servidores web tradicionales, Varnish está específicamente construido para almacenar en caché y servir contenido en caché a velocidades excepcionales.

Características clave:

  • Caché en memoria: Almacena objetos en caché en RAM para acceso ultra rápido
  • Arquitectura de proxy inverso: Se sitúa frente a los servidores web backend
  • Scripting VCL: Poderoso lenguaje de configuración para control fino de caché
  • Edge Side Includes (ESI): Permite caché de página parcial
  • Balanceo de carga: Puede distribuir solicitudes entre múltiples backends

Cómo Funciona Varnish

  1. Recepción de Solicitud: El cliente envía solicitud HTTP a Varnish
  2. Búsqueda en Caché: Varnish verifica si el contenido existe en caché
  3. Acierto de Caché: Si se encuentra, Varnish sirve el contenido en caché inmediatamente
  4. Fallo de Caché: Si no se encuentra, Varnish reenvía la solicitud al backend
  5. Respuesta del Backend: El backend procesa la solicitud y devuelve la respuesta
  6. Almacenamiento en Caché: Varnish almacena la respuesta en caché y la sirve al cliente
  7. Solicitudes Subsiguientes: Futuras solicitudes del mismo contenido se sirven desde caché

Beneficios de Varnish Cache

Ganancias de Rendimiento:

  • 50-1000x tiempos de respuesta más rápidos comparado con procesamiento backend
  • Reduce la carga del backend en 80-95% para contenido cacheable
  • Maneja picos de tráfico alto sin sobrecarga del backend
  • Experiencia de usuario mejorada a través de cargas de página más rápidas

Escalabilidad:

  • Manejar miles de conexiones simultáneas eficientemente
  • Servir millones de solicitudes por día desde hardware moderado
  • Escalar horizontalmente con múltiples instancias de Varnish

Flexibilidad:

  • Potente scripting VCL para lógica de caché personalizada
  • Soporte para diferentes servidores backend
  • Estrategias avanzadas de invalidación de caché

Eficiencia de Costos:

  • Reducir costos de infraestructura manejando más tráfico con menos servidores
  • Menor uso de ancho de banda a través de caché eficiente

Instalación

Instalando Varnish en Ubuntu/Debian

Usando el repositorio oficial de Varnish (recomendado para última versión):

# Actualizar índice de paquetes
sudo apt update

# Instalar prerrequisitos
sudo apt install -y debian-archive-keyring curl gnupg apt-transport-https

# Agregar clave GPG de Varnish
curl -fsSL https://packagecloud.io/varnishcache/varnish70/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/varnishcache-archive-keyring.gpg

# Agregar repositorio de Varnish (Varnish 7.0 LTS)
echo "deb [signed-by=/usr/share/keyrings/varnishcache-archive-keyring.gpg] https://packagecloud.io/varnishcache/varnish70/ubuntu/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/varnishcache-varnish70.list

# Actualizar índice de paquetes
sudo apt update

# Instalar Varnish
sudo apt install -y varnish

# Verificar instalación
varnishd -V

Usando repositorio predeterminado de Ubuntu (versión más antigua):

# Instalar Varnish desde repositorio predeterminado
sudo apt update
sudo apt install -y varnish

# Verificar versión
varnishd -V

Instalando Varnish en CentOS/Rocky Linux

# Instalar repositorio EPEL
sudo dnf install -y epel-release

# Agregar repositorio de Varnish (Varnish 7.0)
sudo curl -s https://packagecloud.io/install/repositories/varnishcache/varnish70/script.rpm.sh | sudo bash

# Instalar Varnish
sudo dnf install -y varnish

# Verificar instalación
varnishd -V

# Habilitar e iniciar Varnish
sudo systemctl enable varnish
sudo systemctl start varnish

Archivos de Configuración Iniciales

Después de la instalación, los archivos de configuración clave se encuentran en:

  • /etc/varnish/default.vcl: Archivo principal de configuración VCL
  • /etc/default/varnish (Ubuntu/Debian) o /etc/varnish/varnish.params (CentOS): Parámetros del servicio
  • /etc/systemd/system/varnish.service: Archivo de servicio systemd
  • /var/lib/varnish: Directorio de almacenamiento de caché

Configuración Básica

Configurando el Puerto de Varnish

Por defecto, Varnish escucha en el puerto 6081. Para uso en producción, configúrelo para escuchar en el puerto 80.

Paso 1: Reconfigurar servidor web backend

Primero, cambie su servidor web backend (Apache/Nginx) para escuchar en un puerto diferente:

Para Apache (/etc/apache2/ports.conf):

# Cambiar de:
Listen 80

# A:
Listen 8080

Actualizar virtual hosts:

# Ubuntu/Debian
sudo sed -i 's/:80/:8080/g' /etc/apache2/sites-available/*.conf

# Reiniciar Apache
sudo systemctl restart apache2

Para Nginx (/etc/nginx/sites-available/default):

# Cambiar de:
listen 80;

# A:
listen 8080;

Reiniciar Nginx:

sudo systemctl restart nginx

Paso 2: Configurar Varnish para escuchar en puerto 80

Editar parámetros del servicio Varnish:

# Ubuntu/Debian
sudo nano /etc/default/varnish

# CentOS/Rocky Linux
sudo nano /etc/varnish/varnish.params

Configurar los siguientes parámetros:

# Dirección y puerto de escucha de Varnish
VARNISH_LISTEN_ADDRESS=0.0.0.0
VARNISH_LISTEN_PORT=80

# Almacenamiento de caché
# malloc: almacenamiento basado en RAM
# file: almacenamiento basado en disco
VARNISH_STORAGE="malloc,256M"

# Archivo de configuración VCL
VARNISH_VCL_CONF=/etc/varnish/default.vcl

# Interfaz de administración
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082

# Archivo secreto para autenticación de administración
VARNISH_SECRET_FILE=/etc/varnish/secret

Paso 3: Actualizar archivo de servicio systemd

Crear o editar la sobrescritura de systemd:

# Crear directorio de sobrescritura de systemd
sudo mkdir -p /etc/systemd/system/varnish.service.d/

# Crear configuración de sobrescritura
sudo nano /etc/systemd/system/varnish.service.d/override.conf

Agregar el siguiente contenido:

[Service]
ExecStart=
ExecStart=/usr/sbin/varnishd \
  -a :80 \
  -T localhost:6082 \
  -f /etc/varnish/default.vcl \
  -S /etc/varnish/secret \
  -s malloc,256m

Recargar systemd y reiniciar Varnish:

# Recargar daemon systemd
sudo systemctl daemon-reload

# Reiniciar Varnish
sudo systemctl restart varnish

# Verificar que Varnish esté ejecutándose en puerto 80
sudo ss -tlnp | grep :80
# Debería mostrar varnishd escuchando en puerto 80

Configuración Básica de VCL

Editar el archivo VCL principal para configurar su backend:

sudo nano /etc/varnish/default.vcl

Configuración básica de VCL:

vcl 4.1;

# Definición de backend
backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .connect_timeout = 600s;
    .first_byte_timeout = 600s;
    .between_bytes_timeout = 600s;
}

# Recibir solicitud del cliente
sub vcl_recv {
    # Eliminar encabezados X-Forwarded-For existentes
    unset req.http.X-Forwarded-For;
    set req.http.X-Forwarded-For = client.ip;

    # Normalizar encabezado Accept-Encoding
    if (req.http.Accept-Encoding) {
        if (req.url ~ "\.(jpg|jpeg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|swf|woff|woff2|ttf|eot)$") {
            # Formatos ya comprimidos, no modificar
            unset req.http.Accept-Encoding;
        } elsif (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
        } elsif (req.http.Accept-Encoding ~ "deflate") {
            set req.http.Accept-Encoding = "deflate";
        } else {
            unset req.http.Accept-Encoding;
        }
    }

    # No cachear solicitudes POST, PUT, DELETE
    if (req.method != "GET" && req.method != "HEAD") {
        return (pass);
    }

    # No cachear solicitudes con autorización
    if (req.http.Authorization) {
        return (pass);
    }

    # No cachear áreas de administración
    if (req.url ~ "^/admin" || req.url ~ "^/wp-admin") {
        return (pass);
    }

    # Cachear todo lo demás
    return (hash);
}

# Manejar respuesta del backend
sub vcl_backend_response {
    # Cachear archivos estáticos por 1 hora
    if (bereq.url ~ "\.(jpg|jpeg|png|gif|css|js|ico|woff|woff2|ttf|eot|svg)$") {
        set beresp.ttl = 1h;
        unset beresp.http.Set-Cookie;
    }

    # No cachear cookies
    if (beresp.http.Set-Cookie) {
        set beresp.ttl = 0s;
        set beresp.uncacheable = true;
        return (deliver);
    }

    # Tiempo de caché predeterminado
    set beresp.ttl = 5m;

    return (deliver);
}

# Entregar respuesta al cliente
sub vcl_deliver {
    # Agregar encabezado de estado de caché para depuración
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
        set resp.http.X-Cache-Hits = obj.hits;
    } else {
        set resp.http.X-Cache = "MISS";
    }

    # Eliminar encabezados del backend por seguridad
    unset resp.http.Server;
    unset resp.http.X-Powered-By;
    unset resp.http.X-Varnish;
    unset resp.http.Via;

    return (deliver);
}

Probar y recargar VCL:

# Probar sintaxis VCL
sudo varnishd -C -f /etc/varnish/default.vcl

# Recargar Varnish con nueva configuración
sudo systemctl reload varnish

# Verificar que Varnish esté funcionando
curl -I http://localhost

Lenguaje de Configuración VCL

Fundamentos de VCL

VCL (Varnish Configuration Language) es un lenguaje específico de dominio para definir políticas de caché. Consiste en subrutinas que se ejecutan en diferentes etapas del procesamiento de solicitudes.

Subrutinas VCL clave:

  • vcl_recv: Llamada cuando se recibe solicitud del cliente
  • vcl_backend_fetch: Llamada antes de enviar solicitud al backend
  • vcl_backend_response: Llamada cuando se recibe respuesta del backend
  • vcl_deliver: Llamada antes de entregar respuesta al cliente
  • vcl_hash: Define componentes de la clave de caché
  • vcl_hit: Llamada cuando se encuentra objeto en caché
  • vcl_miss: Llamada cuando no se encuentra objeto en caché

Lógica Condicional en VCL

sub vcl_recv {
    # Condiciones if-else
    if (req.url ~ "^/api/") {
        # Solicitudes API
        set req.backend_hint = api_backend;
    } elsif (req.url ~ "^/static/") {
        # Contenido estático
        set req.backend_hint = static_backend;
    } else {
        # Backend predeterminado
        set req.backend_hint = default;
    }

    # Coincidencia de expresiones regulares
    if (req.url ~ "\.(css|js|jpg|png|gif|ico|svg)$") {
        # Eliminar cookies para contenido estático
        unset req.http.Cookie;
    }

    # Múltiples condiciones con operadores lógicos
    if (req.http.Cookie && req.url !~ "^/admin") {
        # Manejar cookies excepto para área de administración
        return (hash);
    }
}

Manipulación de Variables

sub vcl_recv {
    # Establecer encabezados personalizados
    set req.http.X-Custom-Header = "value";

    # Concatenar cadenas
    set req.http.X-Full-URL = req.http.host + req.url;

    # Eliminar encabezados
    unset req.http.Cookie;

    # Acceder a información del cliente
    set req.http.X-Client-IP = client.ip;
    set req.http.X-Client-Identity = client.identity;
}

sub vcl_backend_response {
    # Modificar TTL
    set beresp.ttl = 1h;

    # Establecer control de caché
    set beresp.http.Cache-Control = "public, max-age=3600";
}

Políticas de Caché

Configuración de Duración de Caché

Definir diferentes duraciones de caché según el tipo de contenido:

sub vcl_backend_response {
    # Eliminar cookies para contenido cacheable
    if (bereq.url ~ "^/static/" || bereq.url ~ "\.(css|js|jpg|png|gif|ico|svg|woff|woff2)$") {
        unset beresp.http.Set-Cookie;
    }

    # Activos estáticos: 1 semana
    if (bereq.url ~ "\.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|eot)$") {
        set beresp.ttl = 7d;
        set beresp.http.Cache-Control = "public, max-age=604800";
    }
    # Páginas HTML: 10 minutos
    elsif (beresp.http.Content-Type ~ "text/html") {
        set beresp.ttl = 10m;
        set beresp.http.Cache-Control = "public, max-age=600";
    }
    # Respuestas API JSON: 5 minutos
    elsif (beresp.http.Content-Type ~ "application/json") {
        set beresp.ttl = 5m;
        set beresp.http.Cache-Control = "public, max-age=300";
    }
    # Predeterminado: 1 hora
    else {
        set beresp.ttl = 1h;
        set beresp.http.Cache-Control = "public, max-age=3600";
    }

    # Modo grace: servir contenido obsoleto si el backend está caído
    set beresp.grace = 6h;

    return (deliver);
}

Reglas de Omisión de Caché

Configurar cuándo omitir caché:

sub vcl_recv {
    # Omitir caché para patrones de URL específicos
    if (req.url ~ "^/admin" ||
        req.url ~ "^/login" ||
        req.url ~ "^/checkout" ||
        req.url ~ "^/cart") {
        return (pass);
    }

    # Omitir caché para usuarios autenticados
    if (req.http.Authorization || req.http.Cookie ~ "sessionid") {
        return (pass);
    }

    # Omitir caché para métodos POST, PUT, DELETE
    if (req.method != "GET" && req.method != "HEAD") {
        return (pass);
    }

    # Omitir caché cuando hay encabezado específico presente
    if (req.http.Cache-Control ~ "no-cache") {
        return (pass);
    }

    # Forzar actualización con Ctrl+F5
    if (req.http.Cache-Control ~ "no-cache" || req.http.Pragma ~ "no-cache") {
        set req.hash_always_miss = true;
    }
}

Manejo de Cookies

Manejar adecuadamente cookies para caché óptimo:

sub vcl_recv {
    # Eliminar cookies específicas mientras se mantienen otras
    if (req.http.Cookie) {
        # Eliminar cookies de Google Analytics y otras de rastreo
        set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_ga|_gid|_gat|__utm[a-z]+)=[^;]*", "");
        set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", "");

        # Si no quedan cookies, eliminar el encabezado
        if (req.http.Cookie == "") {
            unset req.http.Cookie;
        }
    }

    # Eliminar cookies para contenido estático
    if (req.url ~ "^/static/" || req.url ~ "\.(css|js|jpg|png|gif|ico|svg|woff|woff2)$") {
        unset req.http.Cookie;
    }
}

sub vcl_backend_response {
    # Eliminar encabezado Set-Cookie para contenido cacheable
    if (bereq.url ~ "^/static/" || bereq.url ~ "\.(css|js|jpg|png|gif|ico|svg)$") {
        unset beresp.http.Set-Cookie;
    }
}

Configuración de Backend

Múltiples Servidores Backend

Configurar múltiples servidores backend para balanceo de carga:

vcl 4.1;

import directors;

# Servidores backend
backend web1 {
    .host = "192.168.1.10";
    .port = "8080";
    .connect_timeout = 5s;
    .first_byte_timeout = 30s;
    .between_bytes_timeout = 5s;
    .probe = {
        .url = "/health";
        .timeout = 2s;
        .interval = 5s;
        .window = 5;
        .threshold = 3;
    }
}

backend web2 {
    .host = "192.168.1.11";
    .port = "8080";
    .connect_timeout = 5s;
    .first_byte_timeout = 30s;
    .between_bytes_timeout = 5s;
    .probe = {
        .url = "/health";
        .timeout = 2s;
        .interval = 5s;
        .window = 5;
        .threshold = 3;
    }
}

backend web3 {
    .host = "192.168.1.12";
    .port = "8080";
    .connect_timeout = 5s;
    .first_byte_timeout = 30s;
    .between_bytes_timeout = 5s;
    .probe = {
        .url = "/health";
        .timeout = 2s;
        .interval = 5s;
        .window = 5;
        .threshold = 3;
    }
}

# Inicializar director para balanceo de carga
sub vcl_init {
    new cluster = directors.round_robin();
    cluster.add_backend(web1);
    cluster.add_backend(web2);
    cluster.add_backend(web3);
}

sub vcl_recv {
    # Establecer sugerencia de backend al balanceador de carga
    set req.backend_hint = cluster.backend();
}

Verificaciones de Salud

Configurar verificaciones de salud del backend:

backend default {
    .host = "127.0.0.1";
    .port = "8080";

    # Configuración de verificación de salud
    .probe = {
        .url = "/health";              # Punto de verificación de salud
        .request =
            "GET /health HTTP/1.1"
            "Host: localhost"
            "Connection: close"
            "User-Agent: Varnish Health Check";
        .timeout = 2s;                 # Tiempo de espera de sonda
        .interval = 5s;                # Verificar cada 5 segundos
        .window = 5;                   # Últimas 5 sondas
        .threshold = 3;                # 3 de 5 deben tener éxito
        .initial = 3;                  # Umbral saludable inicial
    }
}

Configuración de Failover

Implementar failover del backend:

backend primary {
    .host = "primary.example.com";
    .port = "8080";
    .probe = {
        .url = "/health";
        .interval = 5s;
        .timeout = 2s;
        .window = 5;
        .threshold = 3;
    }
}

backend fallback {
    .host = "fallback.example.com";
    .port = "8080";
}

sub vcl_recv {
    # Intentar primario, recurrir a secundario si no está saludable
    if (std.healthy(req.backend_hint)) {
        set req.backend_hint = primary;
    } else {
        set req.backend_hint = fallback;
    }
}

Estrategias Avanzadas de Caché

Edge Side Includes (ESI)

Usar ESI para caché de página parcial:

sub vcl_backend_response {
    # Habilitar procesamiento ESI
    if (beresp.http.Content-Type ~ "text/html") {
        set beresp.do_esi = true;
    }
}

HTML backend con etiquetas ESI:

<!DOCTYPE html>
<html>
<head>
    <title>Mi Sitio Web</title>
</head>
<body>
    <!-- Encabezado en caché (1 día) -->
    <header>
        <esi:include src="/header.html" />
    </header>

    <!-- Contenido dinámico (no cacheado) -->
    <main>
        <esi:include src="/dynamic-content" />
    </main>

    <!-- Pie de página en caché (1 día) -->
    <footer>
        <esi:include src="/footer.html" />
    </footer>
</body>
</html>

Invalidación de Caché

Implementar purga de caché:

# ACL para IPs permitidas para purga
acl purge_allowed {
    "localhost";
    "127.0.0.1";
    "192.168.1.0"/24;
}

sub vcl_recv {
    # Manejar método PURGE
    if (req.method == "PURGE") {
        if (!client.ip ~ purge_allowed) {
            return (synth(405, "Not allowed"));
        }
        return (purge);
    }

    # Manejar método BAN (purga por patrón)
    if (req.method == "BAN") {
        if (!client.ip ~ purge_allowed) {
            return (synth(405, "Not allowed"));
        }
        ban("req.url ~ " + req.url);
        return (synth(200, "Banned"));
    }
}

Purgar caché desde línea de comandos:

# Purgar URL específica
curl -X PURGE http://example.com/path/to/page

# Banear por patrón
curl -X BAN http://example.com/category/*

# Purgar caché completa (¡usar con precaución!)
sudo varnishadm "ban req.url ~ /"

Modo Grace

Servir contenido obsoleto cuando el backend no está disponible:

sub vcl_backend_response {
    # Establecer período de gracia
    set beresp.grace = 6h;  # Servir contenido obsoleto hasta por 6 horas

    # Establecer período de retención
    set beresp.keep = 24h;  # Mantener objetos en caché por 24 horas
}

sub vcl_hit {
    # Si el backend no está saludable, servir contenido obsoleto
    if (obj.ttl >= 0s) {
        # Acierto normal
        return (deliver);
    } elsif (std.healthy(req.backend_hint)) {
        # Backend está saludable, refrescar contenido
        if (obj.ttl + 10s > 0s) {
            set req.http.grace = "normal";
            return (deliver);
        } else {
            return (restart);
        }
    } else {
        # Backend no saludable, servir contenido obsoleto
        return (deliver);
    }
}

Cacheo de Solicitudes POST

Cachear solicitudes POST con criterios específicos:

sub vcl_recv {
    # Hash de solicitudes POST para cachear consultas GraphQL
    if (req.method == "POST" && req.url ~ "^/graphql") {
        # Solo cachear si la consulta está marcada como cacheable
        if (req.http.X-Cache-This == "true") {
            return (hash);
        }
    }
}

sub vcl_hash {
    # Incluir cuerpo POST en clave de caché
    hash_data(req.url);
    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }
    # Agregar cuerpo de solicitud a clave de caché para POST
    if (req.method == "POST") {
        hash_data(req.http.X-Body-Hash);
    }
    return (lookup);
}

Verificación y Pruebas

Verificar Estado de Varnish

Verificar que Varnish esté ejecutándose correctamente:

# Verificar estado del servicio Varnish
sudo systemctl status varnish

# Verificar en qué puerto está escuchando Varnish
sudo ss -tlnp | grep varnish

# Verificar estadísticas de Varnish
varnishstat

# Ver log de Varnish
varnishlog

# Ver solo aciertos y fallos de caché
varnishlog -g request -q "VCL_call eq 'HIT' or VCL_call eq 'MISS'"

Probar Funcionalidad de Caché

Probar si el cacheo está funcionando:

# Primera solicitud (fallo de caché MISS)
curl -I http://example.com/
# Buscar: X-Cache: MISS

# Segunda solicitud (acierto de caché HIT)
curl -I http://example.com/
# Buscar: X-Cache: HIT

# Verificar conteo de aciertos de caché
curl -I http://example.com/ | grep X-Cache-Hits

Monitorear Rendimiento de Caché

# Estadísticas en tiempo real
varnishstat

# Métricas clave a observar:
# - cache_hit: Número de aciertos de caché
# - cache_miss: Número de fallos de caché
# - n_object: Número de objetos en caché
# - n_expired: Número de objetos expirados

# Calcular tasa de aciertos
varnishstat -1 | grep -E 'cache_hit|cache_miss'

# Monitorear contadores específicos
watch -n 1 'varnishstat -1 | grep -E "cache_hit|cache_miss|n_object"'

Depurar Comportamiento de Caché

# Ver flujo detallado de solicitudes
varnishlog -g request

# Filtrar por URL
varnishlog -q "ReqURL ~ '/api/'"

# Ver solo solicitudes backend
varnishlog -g request -i BeginFetch

# Verificar por qué se omitió caché
varnishlog -q "VCL_call eq 'PASS'"

# Ver todos los encabezados
varnishlog -i ReqHeader,RespHeader

Solución de Problemas

Caché No Funciona

Problema: El contenido no se está cacheando

Diagnóstico:

# Verificar estado de caché en encabezados de respuesta
curl -I http://example.com/ | grep X-Cache

# Ver log de Varnish para solicitud específica
varnishlog -q "ReqURL eq '/'"

# Verificar configuración VCL
sudo varnishd -C -f /etc/varnish/default.vcl

Causas comunes:

  1. Cookies previniendo cacheo:
# Solución: Eliminar cookies para contenido cacheable
sub vcl_recv {
    if (req.url ~ "\.(css|js|jpg|png)$") {
        unset req.http.Cookie;
    }
}
  1. Encabezados Cache-Control previniendo cacheo:
# Solución: Sobrescribir control de caché del backend
sub vcl_backend_response {
    set beresp.ttl = 1h;
    set beresp.http.Cache-Control = "public, max-age=3600";
}
  1. Encabezados de autorización:
# Solución: Omitir caché para solicitudes autenticadas
sub vcl_recv {
    if (req.http.Authorization) {
        return (pass);
    }
}

Fallos de Conexión Backend

Problema: 503 Backend Fetch Failed

Diagnóstico:

# Verificar salud del backend
varnishadm backend.list

# Verificar log de errores de Varnish
sudo journalctl -u varnish -f

# Probar backend directamente
curl -I http://localhost:8080

Soluciones:

# Verificar que el backend esté ejecutándose
sudo systemctl status apache2  # o nginx

# Verificar reglas de firewall
sudo iptables -L | grep 8080

# Probar conectividad del backend
telnet localhost 8080

# Aumentar tiempo de espera en VCL
backend default {
    .connect_timeout = 10s;
    .first_byte_timeout = 60s;
}

Problemas de Memoria

Problema: Varnish se queda sin memoria

Diagnóstico:

# Verificar uso de memoria de Varnish
varnishstat -1 | grep -E 'SMA|storage'

# Ver tamaño de caché
du -sh /var/lib/varnish/

Soluciones:

# Aumentar tamaño de malloc
# Editar /etc/default/varnish o /etc/varnish/varnish.params
VARNISH_STORAGE="malloc,1G"  # Aumentar de 256M a 1G

# O usar almacenamiento basado en archivo
VARNISH_STORAGE="file,/var/lib/varnish/cache,2G"

# Reiniciar Varnish
sudo systemctl restart varnish

Errores de Sintaxis VCL

Problema: VCL falla al compilar

Diagnóstico:

# Verificar sintaxis VCL
sudo varnishd -C -f /etc/varnish/default.vcl

# Ver error detallado
sudo journalctl -u varnish | tail -20

Errores comunes:

  1. Punto y coma faltante:
# Incorrecto:
set req.http.X-Custom = "value"

# Correcto:
set req.http.X-Custom = "value";
  1. Declaración de retorno inválida:
# Incorrecto:
sub vcl_recv {
    return (cache);  # 'cache' no es válido
}

# Correcto:
sub vcl_recv {
    return (hash);  # Usar 'hash' para cacheo
}

Mejores Prácticas

Optimización de Rendimiento

  1. Usar memoria suficiente para caché:
# Asignar al menos 1GB por cada 100,000 objetos
VARNISH_STORAGE="malloc,2G"
  1. Optimizar valores TTL:
# Equilibrar frescura vs. rendimiento
# Activos estáticos: días/semanas
# Contenido dinámico: minutos/horas
# Respuestas API: segundos/minutos
  1. Habilitar compresión:
sub vcl_backend_response {
    if (beresp.http.content-type ~ "text|javascript|json|css|xml") {
        set beresp.do_gzip = true;
    }
}
  1. Usar modo grace para alta disponibilidad:
set beresp.grace = 6h;  # Servir obsoleto si el backend falla

Endurecimiento de Seguridad

  1. Restringir acceso de purga:
acl purge_allowed {
    "localhost";
    "127.0.0.1";
    # No permitir acceso público
}
  1. Ocultar encabezados internos:
sub vcl_deliver {
    unset resp.http.X-Varnish;
    unset resp.http.Via;
    unset resp.http.X-Powered-By;
}
  1. Implementar limitación de tasa:
import std;
import vsthrottle;

sub vcl_recv {
    if (vsthrottle.is_denied(client.identity, 100, 10s)) {
        return (synth(429, "Too Many Requests"));
    }
}

Monitoreo y Mantenimiento

  1. Monitoreo regular:
# Monitorear tasa de aciertos de caché (debería ser > 80%)
varnishstat -1 | grep cache_hit

# Observar errores
varnishlog -q "RespStatus >= 500"

# Monitorear uso de memoria
varnishstat -1 | grep -E 'SMA|storage'
  1. Rotación de logs:
# Asegurar que los logs de Varnish se roten
sudo nano /etc/logrotate.d/varnish
  1. Calentamiento regular de caché:
# Script para calentar caché después de reinicios
for url in /page1 /page2 /page3; do
    curl -s http://example.com$url > /dev/null
done

Estrategia de Cacheo

  1. Cachear selectivamente: No todo debe ser cacheado
  2. Establecer TTLs apropiados: Equilibrar frescura y rendimiento
  3. Usar modo grace: Mejorar disponibilidad durante problemas del backend
  4. Implementar invalidación de caché: Mantener contenido fresco
  5. Monitorear tasas de aciertos: Optimizar basado en datos reales

Conclusión

Varnish Cache es un acelerador HTTP excepcionalmente potente que puede transformar el perfil de rendimiento de su aplicación web. Al cachear inteligentemente contenido en memoria y servirlo a velocidades relámpago, Varnish reduce la carga del backend, mejora los tiempos de respuesta y permite que su infraestructura maneje significativamente más tráfico.

Puntos clave de esta guía:

  • Instalación y configuración apropiadas: Configurar Varnish para escuchar en puerto 80 con backend en puerto alternativo
  • Dominio de VCL: Usar VCL para implementar políticas de caché sofisticadas
  • Configuración de backend: Configurar verificaciones de salud y balanceo de carga para confiabilidad
  • Políticas de caché: Definir TTLs apropiados y reglas de omisión para diferentes tipos de contenido
  • Características avanzadas: Aprovechar ESI, modo grace e invalidación de caché
  • Monitoreo y optimización: Monitorear continuamente el rendimiento y optimizar configuraciones

Varnish Cache es particularmente efectivo para sitios web con mucho contenido, aplicaciones de alto tráfico y APIs donde las operaciones de lectura superan significativamente a las escrituras. Combinado con estrategias apropiadas de invalidación de caché, configuración inteligente de TTL y monitoreo integral, Varnish proporciona la aceleración de rendimiento necesaria para aplicaciones web modernas.

Recuerde que el cacheo es un acto de equilibrio entre rendimiento y frescura. Comience con valores TTL conservadores, monitoree tasas de aciertos de caché y optimice gradualmente según los requisitos específicos de su aplicación y patrones de tráfico. Con configuración y monitoreo apropiados, Varnish Cache puede reducir tiempos de respuesta de cientos de milisegundos a milisegundos de un solo dígito mientras reduce la carga del backend en 80-95%.

Continúe aprendiendo explorando temas avanzados como Módulos de Varnish (VMODs), funciones VCL personalizadas, integración con CDNs y estrategias avanzadas de balanceo de carga para mejorar aún más su infraestructura de caché.