Cómo un load balancer decide a quién mandarle tu request

Jorge SaavedraJorge Saavedra
·15 de diciembre, 2023·8 min de lectura
load balanceralgoritmosround robinleast connectionsnetworking
Cada vez que abres una página web, tu request viaja por internet hasta llegar a un servidor. Pero en la mayoría de aplicaciones serias no hay un solo servidor, hay varios. Puede haber 3, 10 o 50 copias de la misma aplicación corriendo al mismo tiempo. Y alguien tiene que decidir cuál de esas copias atiende tu request.
Ese alguien es el load balancer. Recibe tu request, mira las opciones disponibles y en milisegundos decide a quién mandárselo. Pero esa decisión no es trivial. Dependiendo de cómo la tome, tu experiencia puede ser rápida y fluida, o lenta y frustrante. Los algoritmos que usa para tomar esa decisión son el tema de este post.

Round Robin

Imagina un repartidor de cartas en una mesa de juego. El repartidor le da una carta al jugador 1, la siguiente al jugador 2, la siguiente al jugador 3, y vuelve al jugador 1. No importa si el jugador 2 ya tiene muchas cartas o si el jugador 3 va perdiendo. El turno es el turno. Simple, predecible, sin favoritismos.
Con round robin
round robin

Algoritmo de distribución que asigna requests a los servidores en orden rotativo. El primer request va al servidor A, el segundo al B, el tercero al C, y el cuarto vuelve al A. Cada servidor recibe exactamente la misma cantidad de requests.

el load balancer hace exactamente eso. Mantiene una lista de servidores y un puntero que avanza en orden. R1 va al servidor A, R2 va al B, R3 va al C, R4 vuelve al A. Sin lógica adicional, sin estado que mantener, sin cálculos costosos.

Round Robin: distribución en orden rotativo

RequestsR1R2R3R4R5R6ServidoresServidor AR1, R4Servidor BR2, R5Servidor CR3, R6
Funciona perfecto cuando todos tus servidores tienen la misma capacidad y cuando los requests tienen un costo similar. Si tienes 3 instancias idénticas atendiendo requests de login, por ejemplo, round robin te da una distribución equitativa sin gastar un solo ciclo de CPU en decidir.
El problema aparece cuando los requests no son iguales. Si el servidor A recibe un request que tarda 10 segundos, round robin no sabe eso. Sigue mandando requests al servidor A en su turno, aunque esté ahogado, mientras el B y el C esperan sin hacer nada. La equidad en la cantidad no garantiza equidad en la carga real.

Least Connections

Cambias de estrategia. En lugar de ir a la siguiente caja del supermercado en orden, miras todas las filas y vas a la que tiene menos personas. No sigues ningún turno. Solo observas el estado actual y eliges el camino más despejado.
Así funciona Least Connections. El load balancer mantiene un conteo de las conexiones activas
conexiones activas

Requests que un servidor está procesando en este momento. Un request llega, se abre una conexión. Cuando el servidor termina y responde, la conexión se cierra. El conteo activo refleja cuánto trabajo tiene el servidor en este instante.

de cada servidor y manda el siguiente request al que tenga menos. Si el servidor A tiene 5 conexiones abiertas, el B tiene 2 y el C tiene 4, el próximo request va al B sin dudarlo.

Least Connections: el próximo request va al servidor menos ocupado

Servidor A5 conexionesServidor B2 conexiones ✓Servidor C4 conexionespróximo request
Este algoritmo es mucho más inteligente cuando los requests tienen duraciones variables. Un endpoint que hace una consulta pesada a la base de datos no pesa lo mismo que uno que devuelve un valor en memoria. Least Connections se adapta a eso naturalmente. El servidor que termina más rápido libera conexiones antes, y el load balancer se lo premia mandándole más tráfico.
Hay un caso que puede salir mal. Si un servidor es lento, termina sus requests despacio, por lo que casi siempre tiene pocas conexiones abiertas. El load balancer ve eso como disponibilidad y le sigue mandando trabajo. El resultado es el opuesto al que quieres, el servidor más lento recibe más carga. Es una trampa difícil de detectar sin métricas de latencia.

IP Hash

Hay un restaurante donde siempre te sientan en la misma mesa. No importa si vienes el martes o el sábado, si la mesa está ocupada o libre, el mesero te lleva al mismo lugar de siempre. Tienes tu lugar, ya saben qué pides, y todo funciona con menos fricción.
IP Hash hace lo mismo. El load balancer toma tu dirección IP, le aplica una función de hash
hash

Función matemática que convierte una entrada de longitud variable (como una IP) en un número fijo. La misma entrada siempre produce el mismo número. Ese número se usa para determinar a qué servidor va el request.

y el resultado determina a qué servidor vas. Como la misma IP siempre produce el mismo hash, siempre terminas en el mismo servidor. Eso es lo que se llama sticky sessions
sticky sessions

Configuración donde los requests de un mismo usuario siempre llegan al mismo servidor. Útil cuando el servidor guarda estado del usuario en memoria (sesión, caché local) y necesita que los requests siguientes encuentren ese estado.

.

IP Hash: la misma IP siempre llega al mismo servidor

IPs192.168.1.1010.0.0.5172.16.0.1hash()ip → servidorServidoresServidor AServidor BServidor C
Esto es muy útil cuando tu servidor guarda estado del usuario en memoria. Una sesión de autenticación, un caché local con las preferencias del usuario, datos temporales de una operación de varios pasos. Si el siguiente request del mismo usuario llega a un servidor diferente, ese estado no existe y el usuario tiene un error o tiene que volver a hacer login.
El punto débil de IP Hash aparece cuando el número de servidores cambia. Cuando agregas o quitas instancias con autoscaling, el hash se recalcula para todas las IPs. Tu "mesa de siempre" desaparece y todos los usuarios quedan asignados a nuevos servidores, perdiendo el estado que tenían guardado. Es el costo de la rigidez que ofrece la consistencia.

¿Cuál usar?

La mayoría de los load balancers modernos usan Round Robin o variantes de Least Connections como configuración por defecto. El Application Load Balancer de AWS, por ejemplo, usa Round Robin por defecto y tiene Least Outstanding Requests como alternativa. Si tu aplicación no guarda estado en el servidor y los requests tienen duración similar, Round Robin es suficiente y tiene menos overhead. Si hay variación en la duración de los requests, Least Connections te va a dar una distribución más pareja. IP Hash es el menos común porque empuja hacia aplicaciones con estado en el servidor, algo que en arquitecturas modernas se prefiere evitar.
Si quieres ver cómo el load balancer interactúa con la cantidad de servidores que están corriendo en un momento dado, el post sobre autoscaling en AWS ECS continúa desde donde termina este. Cuando las instancias se agregan y se eliminan dinámicamente, la forma en que el load balancer distribuye el tráfico se vuelve todavía más importante.

Posts que podrian interesarte