Load balancing, proxies y API gateways | Nicolás Garzón
La capa de entrada recibe tráfico, aplica políticas técnicas y dirige solicitudes a destinos capaces de procesarlas. Su objetivo es proteger y distribuir, no convertirse en un segundo dominio lleno de reglas de negocio.
Cuando una aplicación tiene varias instancias o regiones, el cliente necesita una puerta de entrada estable.
Texto
Copiar cliente
→ DNS / edge
→ load balancer o reverse proxy
→ gateway
→ servicio o instanciaCada capa puede aportar routing, TLS, límites, observabilidad y protección. Sin disciplina, la cadena acumula timeouts, retries y transformaciones que vuelven difícil saber dónde falló una solicitud.
Supón tres instancias de una API.
Sin balanceador, el cliente tendría que conocerlas y detectar cuál está disponible.
Texto
Copiar request
→ seleccionar destino saludable
→ enviar
→ observar resultadoEl balanceador oculta topología y permite reemplazar instancias. Sin embargo, solo funciona bien si puede distinguir capacidad real, evitar destinos degradados y retirar instancias de forma segura.
Opera con conexiones TCP/UDP, IP y puerto.
Menor procesamiento de protocolo.
Alto throughput.
Puede transportar protocolos no HTTP.
Menos contexto para routing.
No conoce paths, headers ni semántica HTTP.
Comprende HTTP y puede decidir por:
Host.
Path.
Header.
Cookie.
Método.
Identidad técnica.
Permite canary releases, routing por versión y políticas más expresivas. A cambio añade parsing, configuración y superficie de seguridad.
Un reverse proxy representa a servidores internos frente al cliente.
Terminar TLS.
Reutilizar conexiones.
Comprimir.
Cachear.
Normalizar headers.
Aplicar límites de tamaño.
Ocultar topología.
Registrar métricas.
Debe preservar información confiable como IP, protocolo y trace context sin aceptar headers falsificados desde clientes no confiables.
Un gateway centraliza políticas comunes de APIs:
Autenticación inicial.
Routing.
Cuotas.
Rate limiting.
Transformación limitada.
Observabilidad.
Versionado de entrada.
Agregación controlada.
La autorización de negocio permanece cerca del dominio.
Texto
Copiar gateway verifica que el token sea válido
→ Orders verifica que el actor puede confirmar ese pedido del tenantEl gateway no debería decidir reglas como “un cajero solo puede cancelar pedidos antes de preparación”, porque ese conocimiento pertenece al contexto.
Funciona cuando capacidad y duración son similares.
Problema: una instancia lenta recibe la misma cantidad que una rápida.
Asigna más tráfico a destinos con mayor capacidad.
Máquinas diferentes.
Migraciones.
Canary releases.
Regiones con distinto tamaño.
Los pesos estáticos pueden quedar obsoletos durante degradación.
Prefiere el destino con menos conexiones activas.
Ayuda cuando las solicitudes tienen duraciones variables.
No siempre representa carga real: una conexión puede estar ociosa y otra consumir CPU intensa.
Cuenta requests en vuelo. Es más útil para HTTP que conexiones persistentes.
Usa una clave para mantener afinidad aproximada.
Caché distribuida.
Sesiones.
Routing por tenant.
Riesgo: una clave caliente concentra tráfico.
Favorece destinos con menor latencia observada.
Puede reaccionar a degradación, pero necesita suavizado para no producir oscilación.
Un algoritmo no compensa una instancia saturada si sigue marcada como saludable.
Requests activos.
Latencia reciente.
Error rate.
Queue depth.
CPU.
Conexiones disponibles.
Readiness.
Los mecanismos adaptativos deben evitar flapping: mover tráfico demasiado rápido puede sobrecargar la siguiente instancia.
Un único endpoint /health suele mezclar conceptos distintos.
Indica si la inicialización terminó.
Mientras falla, el proceso no debería recibir tráfico ni ser reiniciado por lentitud normal de arranque.
Indica si el proceso puede progresar.
Debe detectar deadlock o estado irrecuperable local.
No debería fallar solo porque una dependencia externa está caída; reiniciar todas las instancias no corrige PostgreSQL o un proveedor.
Indica si puede aceptar tráfico ahora.
No existe conexión crítica.
El proceso está drenando.
El pool está agotado de forma persistente.
La instancia no cargó configuración.
Verifica dependencias con mayor profundidad para diagnóstico, no necesariamente para routing cada pocos segundos.
Si readiness consulta todas las dependencias y una falla, el balanceador puede retirar todas las instancias.
Texto
Copiar Payments caído
→ todas las APIs no ready
→ también se pierde catálogo y perfilLa readiness debe representar capacidad de atender el tráfico asignado y considerar degradación parcial.
Antes de terminar una instancia:
Marcarla no ready.
Detener asignación de requests nuevos.
Completar requests y conexiones existentes.
Dejar de consumir mensajes o tomar trabajos.
Confirmar checkpoints.
Esperar un límite.
Terminar.
Sin draining, despliegues y autoscaling cortan operaciones en vuelo.
Reutilizar conexiones evita handshake y TLS repetidos.
Pero pools mal dimensionados producen:
Demasiadas conexiones al upstream.
Destinos desbalanceados.
Conexiones stale.
Agotamiento de puertos.
Tráfico pegado a instancias antiguas.
El balanceo por conexión puede ser desigual con HTTP/2 o conexiones largas porque muchas solicitudes viajan por una sola conexión.
Connect timeout.
Request timeout.
Idle timeout.
Header timeout.
Stream timeout.
Texto
Copiar cliente: 3 s
gateway: 2,5 s
servicio: 2 s
downstream: 1 sSi el proxy espera 60 s y el cliente abandona a 3 s, el backend continúa trabajo inútil. Propaga cancelación cuando sea posible.
Un proxy puede reintentar cuando el destino falla antes de procesar.
Es seguro normalmente para:
GET idempotente.
Conexión rechazada antes de enviar.
Operaciones con idempotency key y política explícita.
El upstream pudo completar antes del timeout.
La operación tiene efectos no idempotentes.
Cliente y gateway reintentan simultáneamente.
No existe presupuesto total.
Texto
Copiar cliente: 3 intentos
gateway: 3 intentos
servicio: 3 intentos
→ hasta 27 llamadas downstreamDurante degradación, esto produce tormenta de carga.
Define una capa responsable y un retry budget.
Controla cuántas operaciones acepta el sistema.
IP.
Usuario.
API key.
Tenant.
Endpoint.
Costo de operación.
Región.
Limitar solo IP es insuficiente detrás de NAT o para usuarios autenticados.
Acumula tokens hasta una capacidad y permite bursts.
Suaviza salida a una tasa constante.
Simple, pero permite ráfagas en límites de ventana.
Más preciso, con mayor costo.
La respuesta debe incluir límites y, cuando aplique, Retry-After.
Rate limiting protege velocidad inmediata. Cuotas controlan consumo acumulado:
Requests diarios.
Almacenamiento.
Procesamiento.
Mensajes.
En multi-tenancy, combina límite global con límite por tenant para evitar noisy neighbors.
Cuando la capacidad se agota, rechazar temprano puede preservar el sistema.
Texto
Copiar prioridad alta: pagos, pedidos
prioridad baja: reportes, recomendacionesEl gateway puede rechazar endpoints costosos, pero la prioridad de negocio debe definirse con los dominios.
Un gateway puede dejar de enviar tráfico a un upstream degradado.
Error de una instancia.
Error de todo el servicio.
Error de cliente.
Saturación temporal.
Un circuito global mal configurado puede bloquear un servicio por errores de una región.
Texto
Copiar DNS / global traffic manager
├── región A
│ └── balanceador regional → zonas → instancias
└── región B
└── balanceador regional → zonas → instanciasLa capa global decide por:
Salud regional.
Latencia.
Residencia de datos.
Capacidad.
Preferencia del tenant.
Failover.
La capa regional distribuye dentro de zonas e instancias.
¿Los datos están disponibles en la otra región?
¿Qué RPO existe?
¿La región secundaria soporta toda la carga?
¿Cómo cambia DNS o routing?
¿Cuánto tarda la propagación?
¿Qué sesiones o tokens siguen válidos?
¿Puede existir doble escritura?
Dirigir tráfico sin garantizar datos y capacidad solo mueve el fallo.
Se envía una pequeña proporción a la nueva versión.
Texto
Copiar v1: 95 %
v2: 5 %
Error rate.
Latencia.
Métricas de negocio.
Saturación.
Compatibilidad de schema.
El canary debe representar usuarios reales; enviar solo health checks no valida comportamiento.
Dos entornos completos permiten cambiar routing.
Rollback de tráfico rápido.
Doble infraestructura.
Migraciones de datos difíciles de revertir.
El rollback de aplicación no deshace datos escritos por la nueva versión.
Sticky sessions mantienen un cliente en la misma instancia.
Puede simplificar estado local, pero introduce:
Distribución desigual.
Failover con pérdida de sesión.
Dificultad durante deploy.
Dependencia de cookie o IP.
Tokens firmados.
Estado compartido.
Affinity solo para protocolos que lo requieren.
No la elimines por dogma si WebSocket u otro flujo necesita conexión persistente; diseña recuperación.
Las conexiones largas cambian el balanceo:
Draining necesita más tiempo.
Deploy puede cortar sesiones.
Least connections puede ser relevante.
Estado debe recuperarse.
Heartbeats detectan conexiones muertas.
Backpressure evita buffers infinitos.
Termina en un límite confiable. Si el tráfico interno cruza redes no confiables, considera TLS o mTLS adicional.
El proxy debe eliminar o reemplazar headers como X-Forwarded-For provenientes de clientes.
Configuraciones inconsistentes entre proxies sobre longitud y transferencia pueden permitir interpretar una request de formas distintas.
Mantén parsers y normalización consistentes.
Headers.
Body.
URL.
Tiempo de lectura.
Upload.
Conexiones.
Protege contra consumo de recursos.
Puede bloquear patrones conocidos, pero no reemplaza validación, autorización ni código seguro.
Requests por ruta, tenant y código.
Latencia total y upstream.
Conexiones activas.
Queue time.
Retries.
Rate-limit rejects.
Destinos expulsados.
Health transitions.
Bytes.
TLS errors.
Trace context.
Correlation ID.
Request ID.
Identidad autenticada confiable.
Tenant validado.
No registres secretos, tokens ni bodies sensibles.
Texto
Copiar Internet
→ CDN/WAF
→ load balancer
→ gateway
→ monolito modular
→ PostgreSQL / Redis
Valida token.
Resuelve tenant autorizado.
Aplica rate limit por tenant y actor.
Propaga trace context.
Enruta versiones.
Autoriza operación de negocio.
Protege invariantes.
Decide estados y errores.
Retira instancias no ready.
Distribuye requests.
Drena durante deploy.
El gateway no consulta tablas internas para reglas.
Retries solo para lecturas o comandos idempotentes.
Catálogo puede degradarse desde caché; confirmación de pedido no inventa éxito.
Iniciar instancia nueva.
Completar startup y migraciones compatibles.
Marcar ready.
Enviar canary.
Verificar errores y latencia.
Aumentar tráfico.
Marcar instancia antigua no ready.
Drenar.
Terminar.
Si la nueva versión necesita un schema incompatible, el proceso falla aunque el balanceo sea perfecto. Usa expand-and-contract.
Liveness pasa, readiness quizá también. Usa señales adaptativas, límites y queue depth.
Una dependencia intermitente alterna estado y el balanceador mueve tráfico constantemente. Usa hysteresis y umbrales.
El gateway reintenta un POST y duplica pedido. Exige idempotency key o no reintentar.
El servicio desaparece aunque podría degradarse. Rediseña readiness.
No detecta errores raros. Define duración, volumen y métricas de negocio.
Clientes siguen región antigua. Usa TTL adecuado, anycast o mecanismos complementarios.
Decide fail-open o fail-closed según riesgo. Un endpoint público y una API de pagos pueden elegir distinto.
Centraliza acoplamiento y obliga a desplegarlo por cada cambio. Mantén políticas técnicas en entrada.
Convierte fallos externos en reinicios y retirada masiva.
Envía tráfico a procesos sin capacidad real.
Capas superiores abandonan antes o inferiores cortan operaciones válidas.
Amplifican tráfico y duplican efectos.
Ocultan estado local y dificultan failover.
Castiga usuarios detrás de NAT y no controla tenants autenticados.
Corta requests, mensajes y streams durante deploy.
Retirar una instancia bajo carga.
Deploy con requests largos.
Health flapping.
Upstream lento.
Retry de operación idempotente y no idempotente.
Caída del rate-limit store.
Canary con error funcional.
Failover regional.
WebSocket durante draining.
Header spoofing.
Request y body oversized.
Tenant ruidoso.
Confirmar si el error ocurre en edge, gateway o upstream.
Comparar latencia total y upstream.
Revisar destinos expulsados y health transitions.
Observar queue time, conexiones y saturation.
Revisar retries y rate-limit rejects.
Seguir una traza.
Verificar si el problema afecta región, versión, tenant o endpoint.
Conviene cuando existen múltiples APIs, políticas comunes, clientes externos o necesidad de routing central.
Puede ser innecesario para una aplicación pequeña con un único backend y plataforma gestionada que ya cubre TLS y routing.
No añadas una capa solo para tener un nombre arquitectónico.
El balanceador distribuye tráfico; no corrige capacidad inexistente.
Liveness, readiness y startup responden preguntas distintas.
Draining es necesario para deploy y autoscaling seguros.
Timeouts y retries deben formar un presupuesto coherente.
El gateway aplica políticas técnicas; el dominio conserva autorización e invariantes.
Rate limits deben considerar identidad, tenant y costo.
Failover requiere datos y capacidad, no solo routing.
La capa de entrada debe ser observable y resistente a abuso.
¿Por qué un proceso puede estar live pero no ready?
¿Qué riesgo existe si gateway y cliente reintentan tres veces?
¿Por qué una readiness que consulta todas las dependencias puede reducir disponibilidad?
¿Cuándo consistent hashing ayuda y qué hotspot puede crear?
¿Qué responsabilidades de DomiSys pertenecen al gateway y cuáles a Pedidos?
Ver respuestas orientativas
Puede progresar, pero no tener capacidad, configuración o dependencia crítica para aceptar tráfico.
Amplificación de hasta nueve intentos y duplicación de efectos.
Una dependencia caída retira todas las instancias aunque existan funciones degradables.
Mantiene afinidad por clave, pero una clave popular concentra carga.
Gateway valida identidad y límites; Pedidos autoriza el recurso y protege reglas del pedido.
Patrones de resiliencia utiliza timeouts, límites, circuit breakers, bulkheads y degradación para contener fallos después de que el tráfico entra al sistema.