Configuración de Caché HTTP en HAProxy
HAProxy incorpora desde la versión 1.8 un módulo de caché HTTP nativo que permite almacenar respuestas de los backends y servirlas directamente, reduciendo la latencia y la carga en los servidores de aplicación sin necesidad de herramientas adicionales. Con soporte para control de TTL, gestión de la cabecera Vary, y configuración de tamaño de caché, la caché de HAProxy es una solución ligera ideal para complementar arquitecturas de balanceo de carga en Linux.
Requisitos Previos
- Ubuntu 20.04/22.04 o CentOS/Rocky Linux 8+
- HAProxy 2.0 o superior (la caché es más robusta a partir de 2.x)
- Al menos 512 MB de RAM dedicados a la caché
- Backends HTTP funcionando correctamente
- Acceso root o usuario con privilegios sudo
Instalación de HAProxy
# Ubuntu/Debian: instalar HAProxy desde repositorio oficial
sudo apt-get install -y software-properties-common
sudo add-apt-repository ppa:vbernat/haproxy-2.8
sudo apt-get update
sudo apt-get install -y haproxy=2.8.\*
# CentOS/Rocky Linux
sudo yum install -y haproxy
# Verificar versión instalada
haproxy -v
# Habilitar e iniciar el servicio
sudo systemctl enable haproxy
sudo systemctl start haproxy
Configuración Básica de Caché
La caché en HAProxy se define en tres secciones: global, cache y las referencias en frontend/backend:
sudo cat > /etc/haproxy/haproxy.cfg << 'EOF'
# ================================================================
# Configuración de HAProxy con Caché HTTP
# ================================================================
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
# Máximas conexiones globales
maxconn 50000
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5s
timeout client 50s
timeout server 50s
errorfile 400 /etc/haproxy/errors/400.http
errorfile 503 /etc/haproxy/errors/503.http
# ================================================================
# DEFINICIÓN DE LA CACHÉ
# ================================================================
cache mi_cache
# Tamaño total de la caché en bytes (aquí: 100 MB)
total-max-size 100
# Tamaño máximo de un objeto individual (en bytes)
max-object-size 1048576
# Tiempo de vida por defecto (segundos) cuando el backend no especifica
max-age 60
# Número máximo de entradas en la caché
# (cada entrada tiene un overhead de ~200 bytes en memoria)
# ================================================================
# FRONTEND: Punto de entrada de peticiones
# ================================================================
frontend http_frontend
bind *:80
bind *:443 ssl crt /etc/haproxy/certs/
# Redirigir HTTP a HTTPS
http-request redirect scheme https unless { ssl_fc }
# Activar compresión HTTP
compression algo gzip
compression type text/html text/plain text/css application/json
default_backend app_servers
# ================================================================
# BACKEND: Servidores de aplicación con caché habilitada
# ================================================================
backend app_servers
balance roundrobin
# ---- ACTIVAR CACHÉ EN ESTE BACKEND ----
http-request cache-use mi_cache
http-response cache-store mi_cache
# Servidores backend
server app1 192.168.1.10:8080 check inter 5s rise 2 fall 3
server app2 192.168.1.11:8080 check inter 5s rise 2 fall 3
server app3 192.168.1.12:8080 check inter 5s rise 2 fall 3 backup
EOF
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
sudo systemctl restart haproxy
Gestión del TTL
Controlar cuánto tiempo se almacenan las respuestas:
# Añadir reglas de TTL al bloque backend
sudo cat >> /etc/haproxy/haproxy.cfg << 'EOF'
# ================================================================
# BACKEND CON CONTROL GRANULAR DE TTL
# ================================================================
backend api_backend
balance leastconn
# Activar caché
http-request cache-use mi_cache
http-response cache-store mi_cache
# Reglas de TTL por tipo de respuesta
# (Estas reglas añaden/modifican la cabecera Cache-Control antes de almacenar)
# Para respuestas JSON de la API: cachear 30 segundos
http-response set-header Cache-Control "public, max-age=30" \
if { res.hdr(Content-Type) -m sub application/json }
# Para imágenes: cachear 1 hora
http-response set-header Cache-Control "public, max-age=3600" \
if { res.hdr(Content-Type) -m beg image/ }
# Para respuestas de error: no cachear
http-response set-header Cache-Control "no-store" \
if { status 400:599 }
# Para rutas específicas: TTL corto
http-response set-header Cache-Control "public, max-age=10" \
if { path_beg /api/realtime/ }
server api1 127.0.0.1:3000 check
server api2 127.0.0.1:3001 check
EOF
Configurar TTL máximo en la definición de la caché:
# Editar la sección cache para establecer límites
cat > /tmp/cache-config.txt << 'EOF'
cache mi_cache
total-max-size 200 # 200 MB total
max-object-size 2097152 # 2 MB por objeto
max-age 300 # TTL máximo: 5 minutos (anula valores mayores del backend)
# HAProxy respeta el menor de: max-age del backend o este valor
EOF
echo "Añadir esta configuración a /etc/haproxy/haproxy.cfg"
Gestión de la Cabecera Vary
La cabecera Vary indica que la respuesta varía según cabeceras del cliente:
# HAProxy gestiona automáticamente la caché cuando el backend envía Vary
# Por ejemplo: Vary: Accept-Encoding, Accept-Language
# Ver si el backend envía Vary
curl -I https://mi-app.com/api/datos | grep -i vary
# Configurar límite de variantes en la caché
# En el bloque cache, añadir:
# process-vary on (activo por defecto en HAProxy 2.x)
# Ejemplo: backend que varía por idioma
# Si el backend envía "Vary: Accept-Language", HAProxy almacena
# versiones separadas para cada idioma
# Para deshabilitar el soporte de Vary (si el backend no lo gestiona bien):
# En el bloque backend:
# http-response del-header Vary
# Para forzar una variante específica:
# http-request set-header Accept-Language "es" if { req.hdr(Accept-Language) -m sub es }
Ejemplo de configuración para contenido que varía:
# En el bloque backend del servidor de contenido:
backend content_backend
# Caché con soporte para Vary
http-request cache-use mi_cache
http-response cache-store mi_cache
# Normalizar Accept-Encoding para reducir variantes en caché
# (solo permitir gzip o identity)
http-request set-header Accept-Encoding "gzip" \
if { req.hdr(Accept-Encoding) -m sub gzip }
http-request set-header Accept-Encoding "" \
if ! { req.hdr(Accept-Encoding) -m sub gzip }
server content1 127.0.0.1:4000 check
Optimización del Tamaño
Calibrar la caché según el hardware disponible:
# Calcular el tamaño óptimo de la caché
# Regla general:
# - Reservar máximo el 30-40% de la RAM disponible para la caché
# - Para 4 GB de RAM → máximo 1.2 GB de caché
# - Para 8 GB de RAM → máximo 2.4 GB de caché
# Ver RAM disponible
free -h
# Estimar número de objetos que caben en la caché
# Overhead por objeto: ~200 bytes de metadatos + tamaño del objeto
# Para una caché de 100 MB con objetos de 10 KB de promedio:
# 100 MB / 10 KB = ~10.000 objetos
# Configuración optimizada para 500 MB de caché
cat > /etc/haproxy/conf.d/cache.cfg << 'EOF'
cache mi_cache
# 500 MB de caché total
total-max-size 500
# Objetos de hasta 5 MB (para imágenes grandes)
max-object-size 5242880
# TTL máximo de 10 minutos
max-age 600
EOF
# Incluir el archivo adicional de configuración
# Añadir en haproxy.cfg: include /etc/haproxy/conf.d/*.cfg
Monitorizar el uso de memoria de la caché:
# Ver estadísticas via el socket de administración
echo "show cache" | sudo socat stdio /run/haproxy/admin.sock
# Salida típica:
# 0x... mi_cache: 45 entries (42 unexpired), 1024000/104857600 bytes used
# Aquí: 45 entradas, 42 activas, 1 MB de 100 MB usados
Caché en Frontend y Backend
Configurar la caché con reglas diferentes según la ruta:
sudo cat > /etc/haproxy/haproxy.cfg << 'HAPROXY_EOF'
global
log /dev/log local0
maxconn 50000
daemon
defaults
mode http
log global
option httplog
timeout connect 5s
timeout client 50s
timeout server 50s
# ----------------------------------------------------------------
# Dos zonas de caché con diferentes configuraciones
# ----------------------------------------------------------------
cache cache_estatica
total-max-size 500 # 500 MB para contenido estático
max-object-size 10485760 # 10 MB por objeto
max-age 86400 # 24 horas
cache cache_api
total-max-size 50 # 50 MB para respuestas de API
max-object-size 65536 # 64 KB por objeto de API
max-age 60 # 60 segundos
# ----------------------------------------------------------------
# Frontend principal
# ----------------------------------------------------------------
frontend web
bind *:443 ssl crt /etc/haproxy/certs/
# Usar ACL para enrutar a diferentes backends
acl es_api path_beg /api/
acl es_estatico path_reg \.(jpg|jpeg|png|gif|ico|css|js|woff2|svg)$
use_backend api_cached if es_api
use_backend static_cached if es_estatico
default_backend app_default
# ----------------------------------------------------------------
# Backend para API con caché de corta duración
# ----------------------------------------------------------------
backend api_cached
# Usar caché de API (TTL corto)
http-request cache-use cache_api
http-response cache-store cache_api
# No cachear peticiones autenticadas
http-request cache-use cache_api unless { req.hdr(Authorization) -m found }
http-response cache-store cache_api unless { req.hdr(Authorization) -m found }
server api1 127.0.0.1:3000 check
server api2 127.0.0.1:3001 check
# ----------------------------------------------------------------
# Backend para contenido estático con caché larga
# ----------------------------------------------------------------
backend static_cached
# Usar caché estática (TTL largo)
http-request cache-use cache_estatica
http-response cache-store cache_estatica
# Añadir cabecera de estado de caché para diagnóstico
http-response set-header X-HAProxy-Cache "HIT" if { res.age gt 0 }
server static1 127.0.0.1:9000 check
# ----------------------------------------------------------------
# Backend por defecto (sin caché)
# ----------------------------------------------------------------
backend app_default
server app1 127.0.0.1:8080 check
server app2 127.0.0.1:8081 check
HAPROXY_EOF
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
sudo systemctl reload haproxy
Monitorización de la Caché
Verificar el funcionamiento y rendimiento de la caché:
# Habilitar el panel de estadísticas de HAProxy
sudo cat >> /etc/haproxy/haproxy.cfg << 'EOF'
# Panel de estadísticas de HAProxy
listen stats
bind *:8404
stats enable
stats uri /stats
stats refresh 10s
stats show-node
stats realm "HAProxy Statistics"
stats auth admin:password_stats_seguro
# Información de caché disponible en el panel
EOF
sudo haproxy -c -f /etc/haproxy/haproxy.cfg && sudo systemctl reload haproxy
# Acceder al panel: http://servidor:8404/stats
# Comandos via socket de administración
# Ver estado de la caché
echo "show cache" | sudo socat stdio /run/haproxy/admin.sock
# Ver estadísticas completas
echo "show info" | sudo socat stdio /run/haproxy/admin.sock | grep -i cache
# Script de monitorización de caché
cat > /usr/local/bin/haproxy-cache-monitor.sh << 'EOF'
#!/bin/bash
# Monitorización de caché HAProxy
SOCKET="/run/haproxy/admin.sock"
echo "=== Estado de la Caché HAProxy ==="
echo ""
echo "show cache" | socat stdio "$SOCKET"
echo ""
echo "=== Estadísticas de conexiones ==="
echo "show info" | socat stdio "$SOCKET" | grep -E "MaxConn|CurrConns|Requests"
EOF
chmod +x /usr/local/bin/haproxy-cache-monitor.sh
# Verificar tasa de aciertos via el log
sudo tail -f /var/log/haproxy.log | grep -oP '"[A-Z]+ [^"]*" [0-9]+ [0-9]+'
Solución de Problemas
La caché no almacena respuestas:
# Verificar que HAProxy 2.x está instalado
haproxy -v
# La caché HTTP de HAProxy solo almacena respuestas que:
# 1. Son respuestas a GET o HEAD (no POST)
# 2. El código de respuesta es cacheble (200, 206, 301, 302, etc.)
# 3. El backend envía Cache-Control con max-age > 0
# 4. No tienen Set-Cookie en la respuesta
# 5. No tienen Authorization en la petición
# Verificar que el backend envía cabeceras cacheables
curl -I https://mi-app.com/datos | grep -E "Cache-Control|Set-Cookie"
Error "cache section not found":
# Verificar la versión de HAProxy (caché requiere >= 1.8)
haproxy -v | grep version
# Verificar que la sección cache está en el archivo correcto
sudo haproxy -c -f /etc/haproxy/haproxy.cfg 2>&1
La caché crece demasiado rápido:
# Reducir el TTL máximo
# En la sección cache: max-age 30
# Reducir el tamaño máximo por objeto
# max-object-size 65536 (64 KB)
# Ver qué URLs se cachean más
echo "show cache" | sudo socat stdio /run/haproxy/admin.sock
Conclusión
La caché HTTP integrada en HAProxy proporciona una solución eficiente para reducir la carga en los backends sin necesidad de herramientas adicionales como Varnish o Nginx, simplificando la arquitectura de la infraestructura. Su integración nativa con el sistema de balanceo de carga permite reglas sofisticadas que combinan decisiones de enrutamiento y caché en un único componente, reduciendo la latencia de respuesta y mejorando la resiliencia del sistema ante picos de tráfico en entornos de producción Linux.


