Algoritmos de Equilibrio de Carga Nginx

Nginx proporciona múltiples algoritmos de equilibrio de carga para distribuir tráfico entre servidores upstream basados en diferentes criterios. La selección del algoritmo apropiado depende de los requisitos de su aplicación, estado de sesión, capacidades del servidor y patrones de tráfico. Esta guía cubre todos los algoritmos disponibles, ejemplos de configuración, verificaciones de salud, conexiones keepalive y mejores prácticas.

Tabla de Contenidos

  1. Descripción General del Equilibrio de Carga
  2. Algoritmo Round-Robin
  3. Conexiones Mínimas
  4. IP Hash
  5. Algoritmo Aleatorio
  6. Equilibrio de Carga Ponderado
  7. Algoritmo Least Time
  8. Servidores de Respaldo
  9. Verificaciones de Salud
  10. Conexiones Keepalive
  11. Configuración Avanzada
  12. Monitoreo y Solución de Problemas

Descripción General del Equilibrio de Carga

El equilibrio de carga distribuye solicitudes de cliente entre múltiples servidores backend para mejorar el rendimiento, confiabilidad y utilización de recursos. Nginx evalúa cada solicitud contra los servidores upstream configurados utilizando el algoritmo seleccionado.

Consideraciones clave al elegir un algoritmo:

  • Estado de Sesión: Las aplicaciones con estado necesitan enrutamiento consistente (IP hash, cookie)
  • Capacidad del Servidor: Los servidores heterogéneos necesitan distribución ponderada
  • Patrones de Solicitud: Varían según aplicación (CPU vs I/O intensivo)
  • Salud: Los servidores muertos deben detectarse y removerse
  • Persistencia: Algunas solicitudes necesitan afinidad a servidores específicos

Algoritmo Round-Robin

Round-robin es el algoritmo predeterminado, distribuyendo solicitudes equitativamente en secuencia:

upstream backend {
    server 192.168.1.100:8000;
    server 192.168.1.101:8000;
    server 192.168.1.102:8000;
}

server {
    listen 80;
    server_name api.example.com;
    
    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Distribución de solicitudes con tres servidores:

  • Solicitud 1 → Servidor 1
  • Solicitud 2 → Servidor 2
  • Solicitud 3 → Servidor 3
  • Solicitud 4 → Servidor 1
  • Y así sucesivamente...

Round-robin es apropiado para servidores homogéneos con capacidad idéntica.

Conexiones Mínimas

El algoritmo de conexiones mínimas enruta solicitudes al servidor manejando actualmente las menos conexiones:

upstream backend {
    least_conn;
    
    server 192.168.1.100:8000;
    server 192.168.1.101:8000;
    server 192.168.1.102:8000;
}

server {
    listen 80;
    server_name api.example.com;
    
    location / {
        proxy_pass http://backend;
    }
}

Las conexiones mínimas destacan en:

  • Aplicaciones con conexiones de larga duración
  • Tiempos de procesamiento de solicitud variables
  • Equilibrio de carga de conexiones WebSocket
  • Aplicaciones en tiempo real con conexiones persistentes

El algoritmo mejora la utilización del servidor enrutando a servidores menos ocupados.

IP Hash

IP hash enruta solicitudes del mismo cliente IP al mismo servidor upstream:

upstream backend {
    ip_hash;
    
    server 192.168.1.100:8000;
    server 192.168.1.101:8000;
    server 192.168.1.102:8000;
}

server {
    listen 80;
    server_name api.example.com;
    
    location / {
        proxy_pass http://backend;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Características de IP hash:

  • Asegura afinidad de sesión sin cookies
  • Enrutamiento determinístico (misma IP siempre enruta al mismo servidor)
  • Útil para aplicaciones con estado que requieren persistencia de sesión
  • Reduce misses de caché cuando servidores mantienen cachés locales

Con tres servidores, la función hash enruta consistentemente las solicitudes:

  • Cliente 192.168.100.1 → Servidor A
  • Cliente 192.168.100.2 → Servidor B
  • Cliente 192.168.100.3 → Servidor C

Algoritmo Aleatorio

El algoritmo aleatorio enruta cada solicitud a un servidor upstream seleccionado aleatoriamente:

upstream backend {
    random;
    
    server 192.168.1.100:8000;
    server 192.168.1.101:8000;
    server 192.168.1.102:8000;
}

server {
    listen 80;
    server_name api.example.com;
    
    location / {
        proxy_pass http://backend;
    }
}

Use random con la opción least_conn para seleccionar entre dos servidores aleatorios:

upstream backend {
    random two least_conn;
    
    server 192.168.1.100:8000;
    server 192.168.1.101:8000;
    server 192.168.1.102:8000;
}

Beneficios de random:

  • Distribución simple de carga
  • Reducción de hotspot
  • Apropiado para aplicaciones sin estado
  • random two least_conn proporciona distribución casi óptima con menor costo de CPU

Equilibrio de Carga Ponderado

Asigne pesos a servidores para reflejar diferentes capacidades:

upstream backend {
    server 192.168.1.100:8000 weight=3;  # Recibe 3x más solicitudes
    server 192.168.1.101:8000 weight=1;  # Peso base
    server 192.168.1.102:8000 weight=2;  # Recibe 2x más solicitudes
}

server {
    listen 80;
    server_name api.example.com;
    
    location / {
        proxy_pass http://backend;
    }
}

Con estos pesos, la ratio de distribución de solicitudes es 3:1:2:

  • De 6 solicitudes: Servidor 1 obtiene 3, Servidor 2 obtiene 1, Servidor 3 obtiene 2

Los pesos funcionan con cualquier algoritmo excepto ip_hash:

upstream backend {
    least_conn;
    
    server 192.168.1.100:8000 weight=4;
    server 192.168.1.101:8000 weight=2;
}

Algoritmo Least Time

El algoritmo least time selecciona el servidor con tiempo de respuesta promedio mínimo:

upstream backend {
    least_time header;
    
    server 192.168.1.100:8000;
    server 192.168.1.101:8000;
    server 192.168.1.102:8000;
}

Dos variantes:

  • least_time header: Usa tiempo al primer byte
  • least_time last_byte: Usa tiempo para completar respuesta

Least time combina métricas de tiempo de respuesta con conteo de conexión para optimizar el rendimiento general.

Servidores de Respaldo

Designe servidores como respaldo, usados solo cuando servidores primarios no están disponibles:

upstream backend {
    server 192.168.1.100:8000;
    server 192.168.1.101:8000;
    server 192.168.1.102:8000 backup;
}

server {
    listen 80;
    server_name api.example.com;
    
    location / {
        proxy_pass http://backend;
    }
}

El servidor 192.168.1.102 recibe tráfico solo cuando los Servidores 1 y 2 están abajo.

Use múltiples servidores de respaldo:

upstream backend {
    server 192.168.1.100:8000 weight=5;
    server 192.168.1.101:8000 weight=5;
    server 192.168.1.102:8000 weight=2 backup;
    server 192.168.1.103:8000 weight=2 backup;
}

Verificaciones de Salud

Las verificaciones de salud pasivas detectan fallos cuando fallan solicitudes:

upstream backend {
    server 192.168.1.100:8000 max_fails=3 fail_timeout=30s;
    server 192.168.1.101:8000 max_fails=3 fail_timeout=30s;
    server 192.168.1.102:8000 max_fails=2 fail_timeout=60s;
}

server {
    listen 80;
    server_name api.example.com;
    
    location / {
        proxy_pass http://backend;
        proxy_connect_timeout 2s;
        proxy_read_timeout 5s;
    }
}

Parámetros:

  • max_fails: Número de fallos antes de marcar abajo
  • fail_timeout: Cuánto tiempo esperar antes de reintentar
  • proxy_connect_timeout: Tiempo permitido para conexión
  • proxy_read_timeout: Tiempo permitido para respuesta

Para verificaciones de salud activas, use el módulo health_checks de Nginx Plus o herramientas de terceros.

Conexiones Keepalive

Habilite HTTP keepalive a servidores upstream para reducir la sobrecarga de conexión:

upstream backend {
    server 192.168.1.100:8000;
    server 192.168.1.101:8000;
    server 192.168.1.102:8000;
    
    keepalive 32;
    keepalive_requests 100;
    keepalive_timeout 60s;
}

server {
    listen 80;
    server_name api.example.com;
    
    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Configuraciones críticas:

  • keepalive: Número de conexiones inactivas a mantener por upstream
  • keepalive_requests: Máximo de solicitudes por conexión (reinicia después)
  • keepalive_timeout: Timeout inactivo antes de cerrar
  • proxy_http_version 1.1: Requerido para keepalive HTTP/1.1
  • proxy_set_header Connection "": Elimina encabezado Connection, habilitando keepalive

Configuración Avanzada

Combine múltiples bloques upstream para escenarios especializados:

upstream fast_api {
    least_conn;
    server 192.168.1.110:8000;
    server 192.168.1.111:8000;
}

upstream slow_api {
    server 192.168.1.120:8000;
    keepalive 64;
}

upstream static_content {
    server 192.168.1.130:80;
    keepalive 128;
}

server {
    listen 80;
    server_name api.example.com;
    
    location /api/v1/ {
        proxy_pass http://fast_api;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
    
    location /api/slow/ {
        proxy_pass http://slow_api;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_read_timeout 30s;
    }
    
    location /static/ {
        proxy_pass http://static_content;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

Enrutamiento condicional basado en características de solicitud:

upstream api_servers {
    least_conn;
    server 192.168.1.100:8000;
    server 192.168.1.101:8000;
}

upstream mobile_servers {
    server 192.168.1.150:8000;
    server 192.168.1.151:8000;
}

server {
    listen 80;
    server_name api.example.com;
    
    set $backend "api_servers";
    
    if ($http_user_agent ~* "mobile|android|iphone") {
        set $backend "mobile_servers";
    }
    
    location / {
        proxy_pass http://$backend;
    }
}

Monitoreo y Solución de Problemas

Habilite estadísticas upstream en Nginx:

server {
    listen 8080;
    
    location /nginx_status {
        stub_status;
        access_log off;
        allow 127.0.0.1;
        deny all;
    }
}

Compruebe estado:

curl http://localhost:8080/nginx_status

Verifique la configuración upstream:

nginx -T | grep -A 20 "upstream backend"

Pruebe la conectividad del servidor upstream:

nc -zv 192.168.1.100 8000
curl -v http://192.168.1.100:8000/health

Monitoree los conteos de conexión:

netstat -an | grep ESTABLISHED | wc -l
netstat -an | grep TIME_WAIT | wc -l

Verifique registros de error de Nginx para problemas upstream:

tail -f /var/log/nginx/error.log | grep upstream

Recargue la configuración sin soltar conexiones:

sudo nginx -s reload
sudo systemctl reload nginx

Conclusión

Nginx proporciona algoritmos de equilibrio de carga flexibles y potentes adaptados a requisitos de aplicaciones diversas. Round-robin funciona para servicios sin estado, conexiones mínimas para conexiones persistentes, IP hash para afinidad de sesión y distribución ponderada para infraestructura heterogénea. Combinar estos algoritmos con verificaciones de salud, conexiones keepalive y servidores de respaldo crea configuraciones de equilibrio de carga robustas y resilientes que mantienen alta disponibilidad y rendimiento óptimo.