TechLead
Leccion 3 de 30
7 min de lectura
Diseño de Sistemas

Balanceo de Carga en Profundidad

Inmersión profunda en algoritmos de balanceo de carga, balanceadores L4 vs L7, verificaciones de salud y ejemplos de configuración con Nginx, HAProxy y AWS ELB

¿Qué Es el Balanceo de Carga?

Un balanceador de carga distribuye el tráfico de red entrante entre múltiples servidores para asegurar que ningún servidor individual soporte demasiada carga. Se sitúa entre el cliente y el grupo de servidores, actuando como un proxy inverso que enruta las solicitudes al servidor backend más apropiado.

El balanceo de carga es esencial para lograr alta disponibilidad, fiabilidad y escalabilidad. Sin él, un solo servidor sería un cuello de botella y un punto único de fallo. Con un balanceador de carga, puedes agregar o eliminar servidores del grupo sin ningún tiempo de inactividad, y si un servidor falla, el tráfico se redirige automáticamente a servidores saludables.

Beneficios del Balanceo de Carga

  • Alta Disponibilidad: Si un servidor falla, el balanceador de carga deja de enviarle tráfico y redistribuye a servidores saludables.
  • Escalabilidad: Agrega más servidores detrás del balanceador de carga para manejar mayor tráfico sin cambiar la configuración del cliente.
  • Rendimiento: Distribuye el trabajo uniformemente para evitar que un solo servidor se sature.
  • Flexibilidad: Realiza actualizaciones progresivas eliminando servidores uno a la vez, actualizándolos y agregándolos de vuelta.
  • Terminación SSL: Descarga el cifrado/descifrado TLS de los servidores backend, reduciendo su carga de CPU.

Algoritmos de Balanceo de Carga

El algoritmo determina cómo el balanceador de carga selecciona qué servidor backend debe manejar cada solicitud entrante. La mejor elección depende de las características de tu carga de trabajo.

1. Round Robin

Las solicitudes se distribuyen secuencialmente entre el grupo de servidores. El Servidor 1 recibe la primera solicitud, el Servidor 2 la segunda, el Servidor 3 la tercera, y así sucesivamente, ciclando de vuelta al Servidor 1 después de llegar al último servidor.

2. Round Robin Ponderado

Como round robin, pero a cada servidor se le asigna un peso basado en su capacidad. Un servidor con peso 3 recibe tres veces más solicitudes que un servidor con peso 1.

3. Menos Conexiones

El balanceador de carga envía cada nueva solicitud al servidor con menos conexiones activas. Esto es más inteligente que round robin porque tiene en cuenta la carga real de cada servidor.

4. Menor Tiempo de Respuesta

Envía solicitudes al servidor con el tiempo de respuesta más rápido y menos conexiones activas. Combina el conteo de conexiones con datos reales de rendimiento.

5. Hash de IP

Un hash de la dirección IP del cliente determina qué servidor recibe la solicitud. Esto asegura que el mismo cliente siempre llegue al mismo servidor, lo cual puede ser útil para la persistencia de sesión.

6. Aleatorio

Selecciona un servidor al azar para cada solicitud. Sorprendentemente efectivo con un gran número de servidores debido a la ley de los grandes números.

Comparación de Algoritmos

Algoritmo Complejidad Sesiones Pegajosas Mejor Caso de Uso
Round RobinO(1)NoCargas uniformes
Round Robin PonderadoO(1)NoCapacidades mixtas
Menos ConexionesO(n)NoDuraciones variables
Menor Tiempo de RespuestaO(n)NoApps sensibles a latencia
Hash de IPO(1)Afinidad de sesión necesaria
AleatorioO(1)NoGrandes grupos de servidores

Balanceadores L4 vs L7

Los balanceadores de carga operan en diferentes capas del modelo OSI, y la capa determina qué información está disponible para tomar decisiones de enrutamiento.

Balanceo de Capa 4 (Capa de Transporte)

Los balanceadores L4 trabajan a nivel TCP/UDP. Enrutan tráfico basándose en direcciones IP y números de puerto sin inspeccionar el contenido de los paquetes. Son extremadamente rápidos porque no necesitan descifrar TLS ni analizar cabeceras HTTP.

Balanceo de Capa 7 (Capa de Aplicación)

Los balanceadores L7 operan a nivel HTTP/HTTPS. Pueden inspeccionar la solicitud completa — cabeceras, cookies, ruta URL, cuerpo — y tomar decisiones inteligentes de enrutamiento basadas en esta información. Esto habilita capacidades poderosas como enrutamiento basado en ruta, pruebas A/B y despliegues canary.

Cuándo Usar L4 vs L7

  • Usa L4 cuando: Necesitas rendimiento bruto y baja latencia (ej. servidores de juegos, conexiones de base de datos, streaming en tiempo real), o cuando no necesitas enrutamiento basado en contenido.
  • Usa L7 cuando: Necesitas enrutar basándote en rutas URL (ej. /api a un grupo, /static a otro), necesitas terminación SSL, o requieres funcionalidades avanzadas como pruebas A/B y lanzamientos canary.

Verificaciones de Salud

Las verificaciones de salud son cómo el balanceador de carga sabe si un servidor backend está saludable y capaz de manejar solicitudes. Sin verificaciones de salud, el balanceador de carga podría enviar tráfico a un servidor caído o sobrecargado.

Tipos de Verificaciones de Salud

  • Verificación de Salud TCP: Intenta abrir una conexión TCP al servidor. Si la conexión tiene éxito, el servidor se considera saludable.
  • Verificación de Salud HTTP: Envía una solicitud HTTP GET a un endpoint específico (ej. /health) y verifica una respuesta 200 OK.
  • Verificación de Salud Profunda: El endpoint /health verifica dependencias críticas (base de datos, caché, cola de mensajes) y reporta la salud general del servicio.
// Ejemplo de endpoint de verificación de salud profunda
import express from 'express';

const app = express();

app.get('/health', async (req, res) => {
  const checks = {
    database: false,
    redis: false,
    diskSpace: false,
  };

  try {
    await db.query('SELECT 1');
    checks.database = true;
  } catch (e) {
    console.error('Database health check failed:', e);
  }

  try {
    await redis.ping();
    checks.redis = true;
  } catch (e) {
    console.error('Redis health check failed:', e);
  }

  try {
    const freeSpace = await getDiskSpace();
    checks.diskSpace = freeSpace > 1_000_000_000;
  } catch (e) {
    console.error('Disk space check failed:', e);
  }

  const allHealthy = Object.values(checks).every(Boolean);

  res.status(allHealthy ? 200 : 503).json({
    status: allHealthy ? 'healthy' : 'unhealthy',
    checks,
    uptime: process.uptime(),
    timestamp: new Date().toISOString(),
  });
});

Ejemplos de Configuración de Balanceador de Carga

Configuración de Nginx

Nginx es uno de los balanceadores de carga y proxies inversos de código abierto más populares. Aquí hay una configuración práctica para balanceo de carga HTTP:

upstream backend_servers {
    # Algoritmo de menos conexiones
    least_conn;

    # Servidores backend con verificaciones de salud
    server 10.0.1.10:3000 weight=3 max_fails=3 fail_timeout=30s;
    server 10.0.1.11:3000 weight=2 max_fails=3 fail_timeout=30s;
    server 10.0.1.12:3000 weight=1 max_fails=3 fail_timeout=30s;

    # Servidor de respaldo - solo usado cuando todos los demás están caídos
    server 10.0.1.13:3000 backup;

    # Mantener conexiones vivas a backends
    keepalive 32;
}

server {
    listen 80;
    listen 443 ssl;
    server_name api.example.com;

    # Configuración SSL
    ssl_certificate /etc/ssl/certs/api.example.com.pem;
    ssl_certificate_key /etc/ssl/private/api.example.com.key;

    # Redirigir HTTP a HTTPS
    if ($scheme = http) {
        return 301 https://$host$request_uri;
    }

    location / {
        proxy_pass http://backend_servers;
        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;

        # Timeouts
        proxy_connect_timeout 5s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # Upstream separado para archivos estáticos
    location /static/ {
        proxy_pass http://static_servers;
        proxy_cache static_cache;
        proxy_cache_valid 200 1d;
    }
}

Configuración de HAProxy

global
    maxconn 50000
    log stdout format raw local0

defaults
    mode http
    timeout connect 5s
    timeout client 30s
    timeout server 30s
    option httplog

frontend http_front
    bind *:80
    bind *:443 ssl crt /etc/ssl/certs/combined.pem
    redirect scheme https if !{ ssl_fc }

    # Enrutar basado en ruta URL (L7)
    acl is_api path_beg /api
    acl is_ws hdr(Upgrade) -i websocket

    use_backend api_servers if is_api
    use_backend ws_servers if is_ws
    default_backend web_servers

backend api_servers
    balance leastconn
    option httpchk GET /health
    http-check expect status 200

    server api1 10.0.1.10:3000 check inter 10s fall 3 rise 2
    server api2 10.0.1.11:3000 check inter 10s fall 3 rise 2
    server api3 10.0.1.12:3000 check inter 10s fall 3 rise 2

backend web_servers
    balance roundrobin
    option httpchk GET /
    server web1 10.0.2.10:8080 check
    server web2 10.0.2.11:8080 check

backend ws_servers
    balance source
    server ws1 10.0.3.10:8080 check
    server ws2 10.0.3.11:8080 check

Comparación de Herramientas de Balanceo de Carga

Característica Nginx HAProxy AWS ALB/NLB
TipoL4/L7L4/L7ALB: L7, NLB: L4
Servidor webNoNo
GestionadoNoNo
Terminación SSL
WebSocket
CostoGratis/Código abiertoGratis/Código abiertoPago por uso

Mejores Prácticas

  • Siempre configura verificaciones de salud. Sin ellas, un balanceador de carga enviará tráfico a servidores caídos.
  • Usa drenado de conexiones. Al eliminar un servidor, permite que las conexiones existentes terminen antes de detener el tráfico.
  • Monitorea tu balanceador de carga. Es un componente crítico — si falla, todo lo que está detrás es inalcanzable.
  • Haz el balanceador de carga redundante. Usa pares activo-pasivo o activo-activo para evitar un punto único de fallo.
  • Usa terminación SSL sabiamente. Termina TLS en el balanceador de carga para reducir la carga de CPU en servidores backend, pero usa conexiones cifradas internamente si manejas datos sensibles.

Continuar Aprendiendo