Guía práctica de balanceo de carga con nginx
Muchos desarrolladores usan nginx solo como "proxy inverso + servidor de archivos estáticos", pero en realidad nginx es un balanceador de carga de software bastante potente. Si eres un desarrollador que también administra servidores, dominar nginx puede mejorar significativamente la estabilidad y el rendimiento cuando el tráfico aumenta.
En este artículo, dirigido a desarrolladores principiantes a intermedios, cubriremos:
- Concepto de balanceo de carga
- Cómo configurar el balanceo de carga en nginx
- Algoritmos (round robin, least_conn, ip_hash, etc.)
- Verificación de salud (health check)
- Opciones más usadas
1. ¿Qué es el balanceo de carga?
Balanceo de carga (load balancing) es, en pocas palabras:
"Distribuir las solicitudes entre varios servidores para evitar que uno se sobrecargue."
¿Por qué es necesario?
- Prepararse para picos de tráfico * Evita que un servidor se caiga cuando las solicitudes se concentran.
- Escalabilidad horizontal * En lugar de aumentar la potencia de un solo servidor, se añaden más servidores para aumentar la capacidad.
- Alta disponibilidad * Si un servidor falla, el tráfico se redirige a otros, manteniendo el servicio.
¿Dónde se sitúa nginx?
La arquitectura típica es:
Cliente → nginx (balanceador de carga / proxy inverso) → varios servidores de aplicación
nginx recibe la solicitud y la envía a uno de los servidores de aplicación.
2. Entendiendo la estructura básica del balanceo de carga en nginx
En la configuración de nginx, el balanceo de carga se centra en dos bloques principales:
- Bloque upstream: * Define el "pool" de servidores backend.
- Bloque server / location: * Determina a qué upstream enviar las solicitudes entrantes.
Veamos un ejemplo muy sencillo.
http {
upstream app_backend {
server 10.0.0.101:3000;
server 10.0.0.102:3000;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://app_backend;
# Encabezados de proxy por defecto
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
¿Qué significa esta configuración?
upstream app_backend- Agrupa dos servidores de aplicación (
10.0.0.101:3000y10.0.0.102:3000) en un solo "pool". proxy_pass http://app_backend;- Envía la solicitud del cliente a uno de los servidores del pool.
- Si no se especifica un algoritmo, el predeterminado es round robin.
3. Tipos de algoritmos de balanceo de carga
nginx ofrece varias estrategias de distribución. Elegir la adecuada depende del caso de uso.
3.1 Básico: round robin
Configuración: Si no se indica nada, se usa por defecto
upstream app_backend {
server 10.0.0.101:3000;
server 10.0.0.102:3000;
}
- Primera solicitud → servidor 1
- Segunda solicitud → servidor 2
- Tercera solicitud → servidor 1 …
Ventajas: simple y funciona bien en la mayoría de los casos. Desventajas: no considera la carga actual de cada servidor.
3.2 least_conn (conexiones menos activas)
upstream app_backend {
least_conn;
server 10.0.0.101:3000;
server 10.0.0.102:3000;
}
- Envía nuevas solicitudes al servidor con menos conexiones activas.
- Útil cuando las solicitudes varían mucho en tiempo de respuesta.
Escenarios recomendados
- Algunas peticiones son muy largas, otras rápidas.
- Especificaciones de servidor similares pero patrones de carga desiguales.
3.3 ip_hash (misma IP → mismo servidor)
upstream app_backend {
ip_hash;
server 10.0.0.101:3000;
server 10.0.0.102:3000;
}
- Hashea la IP del cliente para enviar siempre al mismo servidor.
- Útil para sesiones sticky cuando la sesión se guarda en memoria del servidor.
Ventajas
- Mantiene la coherencia de la sesión.
Desventajas
- Al añadir o quitar servidores, el hash cambia y muchos usuarios se mueven.
- Si el cliente está detrás de un proxy (Cloudflare, ELB, etc.), la IP real puede no llegar.
3.4 Distribución basada en peso (weight)
Cuando los servidores tienen especificaciones distintas, se puede asignar más tráfico al más potente.
upstream app_backend {
server 10.0.0.101:3000 weight=3;
server 10.0.0.102:3000 weight=1;
}
- Proporción 3:1 entre servidor 1 y 2.
- Ideal para aprovechar un nuevo servidor más rápido.
4. Health check y manejo de servidores caídos
Para que el balanceador sea realmente inteligente, necesita eliminar automáticamente los servidores caídos.
En la versión de código abierto de nginx, se soporta health check pasivo.
4.1 max_fails / fail_timeout
upstream app_backend {
server 10.0.0.101:3000 max_fails=3 fail_timeout=30s;
server 10.0.0.102:3000 max_fails=3 fail_timeout=30s;
}
max_fails=3→ Si fallan 3 veces consecutivas, el servidor se marca como inactivo.fail_timeout=30s→ Se evita enviar tráfico durante 30 s.- Después, se vuelve a probar y, si responde, se vuelve a usar.
Los "fallos" suelen ser respuestas 502/503/504 o fallos de conexión.
4.2 proxy_next_upstream
Define cuándo pasar la solicitud al siguiente servidor.
location / {
proxy_pass http://app_backend;
proxy_next_upstream error timeout http_502 http_503 http_504;
}
- Si ocurre alguno de los errores listados, se reintenta con el siguiente servidor.
- Evita reintentos excesivos que aumenten la latencia.
5. Ejemplo práctico: balanceo de carga para un servicio web sencillo
Supongamos que tienes dos servidores Node.js corriendo en el puerto 3000.
10.0.0.101:300010.0.0.102:3000
5.1 Configuración de nginx
http {
upstream app_backend {
least_conn;
server 10.0.0.101:3000 max_fails=3 fail_timeout=30s;
server 10.0.0.102:3000 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
server_name myservice.com;
# Proxy de cliente → nginx → Node.js
location / {
proxy_pass http://app_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;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 60s;
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
}
}
}
Con esta configuración:
- Todas las peticiones a
myservice.comllegan a nginx. - nginx las envía al servidor Node.js con menos conexiones activas.
- Si un servidor falla repetidamente, se excluye temporalmente.
6. Terminación de HTTPS (SSL) + balanceo de carga
En producción, casi siempre se usa HTTPS. La práctica más común es usar nginx como terminador SSL.
http {
upstream app_backend {
least_conn;
server 10.0.0.101:3000;
server 10.0.0.102:3000;
}
server {
listen 443 ssl;
server_name myservice.com;
ssl_certificate /etc/letsencrypt/live/myservice.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myservice.com/privkey.pem;
location / {
proxy_pass http://app_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;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# Redirección HTTP → HTTPS
server {
listen 80;
server_name myservice.com;
return 301 https://$host$request_uri;
}
}
- Cliente ↔ nginx: HTTPS
- nginx ↔ servidor de aplicación: HTTP (normalmente interno)
7. ¿Son necesarias las sesiones sticky?
Antes, muchos servidores guardaban la sesión en memoria, por lo que era necesario que el mismo usuario siempre llegara al mismo servidor. Con ip_hash se podía resolver, pero hoy en día se prefieren:
- Almacenar la sesión en Redis u otro almacenamiento externo.
- Usar JWT para una arquitectura sin estado.
Si es posible, elimina el estado a nivel de aplicación y deja que nginx solo distribuya el tráfico. Esto facilita la escalabilidad.
8. Puntos de ajuste comunes
8.1 keepalive
Reutilizar conexiones con el backend mejora el rendimiento.
upstream app_backend {
least_conn;
server 10.0.0.101:3000;
server 10.0.0.102:3000;
keepalive 32;
}
server {
location / {
proxy_pass http://app_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
keepalive 32;→ Cada worker mantiene hasta 32 conexiones keepalive con el backend.- Reduce la latencia y la carga de establecer nuevas conexiones.
8.2 Buffers y timeouts
Para respuestas grandes o backends lentos, ajusta buffers y timeouts.
location / {
proxy_pass http://app_backend;
proxy_buffering on;
proxy_buffers 16 16k;
proxy_busy_buffers_size 64k;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}
- Un
proxy_read_timeoutdemasiado corto puede provocar errores 504. - Ajusta según el patrón de tráfico y la capacidad del backend.
9. Estrategia de adopción de nginx balanceador de carga (paso a paso)
Si ya tienes un servicio funcionando en un solo servidor, puedes escalarlo de la siguiente manera:
- Paso 1: Introducir nginx como proxy inverso * Cliente → nginx → servidor único. * Aprovecha SSL, caché y archivos estáticos.
- Paso 2: Clonar el servidor y configurar upstream
* Añade el nuevo servidor al bloque
upstream. - Paso 3: Health check y monitoreo
* Configura
max_fails,fail_timeout,proxy_next_upstream. * Implementa métricas (Prometheus + Grafana, ELK, etc.). - Paso 4: Ajustes finos
* Selecciona algoritmo (
least_conn,weight). * Habilita keepalive, buffers y timeouts.
Conclusión
nginx no es solo un proxy inverso; su capacidad de balanceo de carga es robusta y versátil.
- Define pools con
upstream. - Elige el algoritmo adecuado (round robin, least_conn, ip_hash, weight).
- Configura health checks y políticas de reintento.
- Termina HTTPS y proxya al backend.
Con estos conocimientos, podrás elevar tu infraestructura y manejar aumentos de tráfico sin sacrificar estabilidad ni rendimiento.

No hay comentarios.