Read in English · Lire en français · Auf Deutsch lesen
Sección 9.2 de 9.8 · Intermedio · 27 min de lectura
Balanceo de carga, ausencia de estado y sesiones
Videolección
5 min · narrado en inglés, con subtítulosSolo escuchar (audio)
Leer la transcripción
Te damos la bienvenida a la sección nueve punto dos. El escalado horizontal te da muchas instancias. Esta lección trata de lo que se sitúa delante de ellas y de cómo repartir el trabajo para que los usuarios nunca noten que las instancias van y vienen.
Imagina un supermercado en el que un empleado dirige a los clientes hacia las cajas. Enviar a la gente a cada caja por turno es justo pero ingenuo. Un cliente con un carro para una familia de seis personas bloquea una caja mientras la siguiente está libre. Enviar a cada cliente a la caja con la cola más corta funciona mucho mejor. El empleado también debe saber qué cajas están abiertas y dejar de enviar gente a una caja que está a punto de cerrar, mientras su cola termina. Y funciona mejor si cualquier caja puede atender a cualquier cliente. Ese es el trabajo de un balanceador de carga.
Un balanceador de carga decide qué instancia recibe cada conexión o solicitud. También comprueba qué instancias están sanas, da a los clientes una dirección estable y a menudo termina TLS. Un balanceador de capa 4 solo ve direcciones IP y puertos. Elige un backend una vez por conexión y la reenvía sin mirar dentro. Eso lo hace extremadamente rápido, y funciona con cualquier protocolo. Un proxy de capa 7 entiende HTTP. Lee cada solicitud, así que puede enrutarlas, reintentarlas, limitar su tasa y registrarlas todas. Aquí enruta por ruta: las solicitudes de pedidos al pool de pedidos, las de la carta al pool de la carta y las búsquedas al pool de búsqueda. Esta diferencia pilla desprevenidos a muchos equipos. gRPC envía muchas solicitudes por una sola conexión de larga duración. Un balanceador de capa 4 elige una vez por conexión, así que las instancias nuevas pueden no recibir nada. gRPC necesita un proxy de capa 7 o un balanceo en el cliente.
¿Qué instancia debería recibir la siguiente solicitud? Toma dos instancias, A y B, que gestionan cada una una solicitud a la vez. Llegan ocho solicitudes separadas por diez milisegundos: primero un informe que tarda cien milisegundos y después siete lecturas de la carta que tardan diez. El round robin envía las solicitudes por turno, cueste lo que cueste cada una. Así que tres lecturas de la carta caen en la instancia A, atascadas detrás del informe. Tardan noventa, ochenta y setenta milisegundos. Las lecturas de la carta tardan de media unos cuarenta y un milisegundos, y la peor, noventa. Mientras tanto, la instancia B está inactiva la mitad del tiempo. Menos conexiones envía cada solicitud a la instancia con menos solicitudes en curso. El informe va a A y, como B siempre vuelve a estar libre a tiempo, todas las lecturas de la carta van a B. Ahora cada lectura de la carta tarda diez milisegundos, y la media de las ocho baja de unos cuarenta y nueve a unos veintiuno. El round robin cuenta solicitudes. Menos conexiones cuenta el trabajo en curso, así que las solicitudes nuevas se alejan automáticamente de una instancia ocupada o lenta.
¿Por qué no elegir siempre la instancia menos cargada del pool? Porque en un sistema grande, decenas de balanceadores ven cada uno solo sus propias solicitudes, o un informe de carga de hace unos segundos. Si todos eligen la instancia que parecía menos cargada, todos eligen la misma. Se ve desbordada, y la manada pasa a la siguiente. Michael Mitzenmacher analizó una alternativa sorprendentemente sencilla: elegir dos instancias al azar y enviar la solicitud a la menos cargada. El azar evita el efecto manada y la comparación evita las peores instancias. Hoy es una opción estándar en proxies como Envoy, y una buena opción predeterminada allí donde haya muchos balanceadores.
Un balanceador debe saber qué instancias pueden recibir tráfico. Una comprobación de actividad pregunta si el proceso está atascado sin posibilidad de recuperarse. Una comprobación de preparación pregunta si debe recibir tráfico en este momento. El error clásico es llamar a la base de datos desde las comprobaciones de actividad. Una breve caída de la base de datos hace fallar todas las comprobaciones, todas las instancias se reinician a la vez y la tormenta de reinicios prolonga la caída. Mantén la comprobación de actividad local y mínima.
Las instancias salen del pool con cada despliegue y cada reducción. El drenaje de conexiones hace que eso no tenga consecuencias. Primero, la instancia recibe una señal de apagado. Su comprobación de preparación falla, así que el balanceador de carga deja de enviarle solicitudes nuevas. Las solicitudes que ya están en curso terminan con normalidad. Las conexiones keep-alive inactivas se cierran, así que los clientes se vuelven a conectar en otro sitio. Después, el proceso termina limpiamente, antes de que se agote su periodo de gracia.
Las aplicaciones más antiguas guardaban la sesión de cada usuario en la memoria de un servidor, así que los balanceadores ofrecían sesiones persistentes. Pero la carga se vuelve desigual y, cuando esa instancia falla, los carritos desaparecen y las personas ven cerrada su sesión. El remedio es sacar el estado de sesión de la instancia. Un token firmado de corta duración puede llevar la identidad del usuario con cada solicitud. Un almacén de sesiones compartido admite un estado más grande y el cierre de sesión inmediato, a costa de una llamada de red por solicitud. Y el estado que debe sobrevivir, como un carrito que el usuario espera encontrar mañana, va en la base de datos. Así, cualquier instancia puede atender cualquier solicitud.
La sección completa trata también el hashing y el balanceo de carga global con DNS y anycast. A continuación, en la sección nueve punto tres, veremos qué ocurre cuando el trabajo llega más deprisa de lo que se puede hacer. Nos vemos allí.
Lo que necesitas saber
- Un balanceador de carga reparte las conexiones o las solicitudes entre las instancias sanas, oculta los cambios de instancias tras una sola dirección y a menudo termina TLS; puede estar en el borde o dentro de los clientes y los sidecars.
- Los balanceadores de capa 4 reenvían conexiones según la dirección y el puerto, rápidos y ajenos al protocolo; los de capa 7 leen cada solicitud HTTP y pueden enrutar, reintentar y limitar la tasa, algo que exigen los protocolos por solicitud como gRPC sobre HTTP/2.
- El round robin ignora el costo de las solicitudes; menos conexiones y el poder de dos elecciones aleatorias (Mitzenmacher) se adaptan a la carga, y las dos elecciones aleatorias evitan el efecto manada que provocan muchos balanceadores cuando todos persiguen la instancia menos cargada.
- Los fallos de actividad (liveness) reinician una instancia y los fallos de preparación (readiness) solo la retiran de la rotación; deja las dependencias compartidas fuera de las comprobaciones de actividad para que un tropiezo de la base de datos no pueda reiniciar toda la flota.
- El drenaje de conexiones deja de enviar solicitudes nuevas a una instancia que se retira y permite que termine el trabajo en curso, así que los despliegues y las reducciones no provocan errores.
- Las sesiones persistentes provocan una carga desigual y la pérdida de sesiones cuando hay fallos; traslada el estado de sesión a tokens firmados, a un almacén compartido o a la base de datos para que cualquier instancia pueda atender cualquier solicitud.
- El balanceo de carga global dirige a los usuarios hacia las regiones mediante las respuestas DNS, limitadas por la caché y los TTL, o mediante anycast, que anuncia una sola dirección desde muchos sitios y deja que el enrutamiento elija el más cercano.
Qué hace un balanceador de carga
Un balanceador de carga se sitúa entre los clientes y un pool de instancias intercambiables y decide, para cada conexión o solicitud, qué instancia la recibe. Repartir es solo una parte del trabajo. Un balanceador de carga también comprueba qué instancias están sanas y deja de enviar tráfico a las que no lo están; da a los clientes una dirección estable mientras las instancias van y vienen con los despliegues y el autoescalado; a menudo termina TLS, de modo que los certificados se gestionan en un solo sitio; y en la capa 7 puede enrutar, reintentar, limitar la tasa y registrar cada solicitud. Es, por tanto, el componente que hace que el escalado horizontal sea invisible para los clientes.
El balanceo de carga aparece en varios niveles. En el borde suele haber un balanceador de carga gestionado en la nube o un par de proxies como HAProxy, NGINX o Envoy. Entre servicios, el balanceo se hace cada vez más en el lado del cliente: una biblioteca cliente de gRPC o un proxy sidecar de una service mesh (Sección 6.3) mantiene la lista de instancias sanas obtenida del descubrimiento de servicios y elige una por sí mismo, lo que elimina un salto de red y un componente central. Sea cual sea la forma, se repiten las mismas decisiones: qué puede ver el balanceador, qué algoritmo usa, cómo decide que una instancia está sana y cómo salen las instancias sin perder trabajo.
Balanceo de carga de capa 4 y de capa 7
Los números de capa proceden del modelo de red OSI. Un balanceador de carga de capa 4 trabaja en la capa de transporte: ve direcciones IP y puertos TCP o UDP, elige un backend cuando se abre una conexión y después reenvía los paquetes de esa conexión sin mirar dentro de ellos. Como hace tan poco, es extremadamente rápido y funciona con cualquier protocolo, incluidas las bases de datos, los intermediarios de mensajes y el tráfico cifrado que no puede leer. Maglev, de Google, y los balanceadores de carga de red de las principales nubes son diseños de capa 4 que gestionan millones de paquetes por segundo.
Un balanceador de carga de capa 7 es un proxy inverso que entiende el protocolo de aplicación, casi siempre HTTP. Termina la conexión del cliente (y normalmente TLS), lee cada solicitud y abre o reutiliza sus propias conexiones con los backends. Eso le permite enrutar por ruta, host, cabecera o cookie (/orders/* al pool de pedidos, /menus/* al pool de la carta), balancear cada solicitud en lugar de cada conexión, reintentar una solicitud fallida en otra instancia, aplicar límites de tasa, añadir cabeceras de trazado y registrar cada solicitud con su estado y su latencia. El costo es más procesamiento por solicitud, un componente que debe guardar las claves TLS y un sitio más en el que hay que configurar los timeouts y los reintentos de forma coherente con el resto del sistema (Sección 9.4).
Hay una diferencia que pilla desprevenidos a muchos equipos. HTTP/2 y gRPC multiplexan muchas solicitudes sobre una sola conexión de larga duración. Un balanceador de capa 4 elige un backend una vez por conexión, así que un cliente que abre una conexión envía todas sus solicitudes a una sola instancia, por muchas instancias que existan: las instancias nuevas que añade el autoescalado no reciben nada hasta que los clientes se vuelven a conectar. Por eso, balancear el tráfico gRPC exige un proxy de capa 7 o un balanceo en el lado del cliente por solicitud.
Una disposición típica en dos niveles
Algoritmos de balanceo de carga
El algoritmo decide qué instancia sana recibe la siguiente conexión o solicitud. Los sencillos ignoran lo ocupadas que están las instancias; los mejores usan alguna medida de la carga; los basados en hash envían deliberadamente las solicitudes relacionadas al mismo sitio. La tabla resume las opciones habituales.
Algoritmos de balanceo de carga habituales
| Algoritmo | Cómo elige | Ventajas | Puntos débiles |
|---|---|---|---|
| Round robin | Cada instancia por turno | Sencillo, predecible, sin estado sobre la carga | Ciego al costo de las solicitudes y a las instancias lentas |
| Round robin ponderado | Por turno, en proporción a pesos configurados | Mezcla tamaños de instancia; aumenta gradualmente el tráfico de las versiones nuevas (canarios) | Los pesos son estimaciones estáticas; sigue siendo ciego a la carga real |
| Aleatorio | Al azar, de forma uniforme | No necesita estado compartido, así que muchos balanceadores pueden usarlo de forma independiente | Desigual por azar, sobre todo con pocas solicitudes |
| Menos conexiones (least connections) (menos solicitudes pendientes) | La instancia con menos solicitudes en curso | Se adapta a costos de solicitud desiguales y a instancias lentas | Necesita recuentos precisos; cada uno de muchos balanceadores solo ve los suyos; las instancias nuevas pueden verse inundadas |
| Ponderado por latencia (por ejemplo, EWMA del tiempo de respuesta) | La instancia con la mejor latencia reciente, a menudo combinada con la carga | Se aparta enseguida de las instancias degradadas | Puede oscilar; una instancia que falla deprisa parece atractiva salvo que se penalicen los errores |
| Hash (IP de origen, cabecera, hashing consistente) | La misma clave va siempre a la misma instancia | Afinidad para cachés y sesiones; el hashing consistente mueve pocas claves cuando cambia el pool | Las claves calientes sobrecargan una instancia; distribución desigual de las claves |
| Poder de dos elecciones aleatorias (power of two choices) | Elige dos instancias al azar y envía a la menos cargada | Casi tan bueno como menos conexiones, sin efecto manada, con poca coordinación | Algo peor que una elección global perfecta con información perfecta |
Ejemplo práctico
Ejemplo práctico: por qué menos conexiones supera al round robin cuando los costos de las solicitudes difieren
Dos instancias, A y B, procesan cada una una solicitud a la vez (las instancias reales tienen más hilos, pero el efecto es el mismo a mayor escala). Llegan ocho solicitudes separadas por 10 ms. La primera es un informe de ventas de un restaurante que cuesta 100 ms; las otras siete son lecturas de la carta que cuestan 10 ms cada una.
| Round robin: asignación | A recibe las solicitudes 1, 3, 5 y 7; B recibe la 2, 4, 6 y 8, sea cual sea su costo |
|---|---|
| Round robin en A | R1 se ejecuta de 0 a 100 ms. R3 (llegó en 20) espera y termina en 110: 90 ms. R5 (40) termina en 120: 80 ms. R7 (60) termina en 130: 70 ms |
| Round robin en B | R2, R4, R6 y R8 terminan cada una 10 ms después de llegar; B está inactiva la mitad del tiempo |
| Resultado del round robin | Lecturas de la carta: 90, 80, 70, 10, 10, 10, 10 ms, media 290 ÷ 7 ≈ 41 ms, peor caso 90 ms. Las ocho solicitudes: media (100 + 290) ÷ 8 ≈ 49 ms |
| Menos conexiones: asignación | R1 va a A (ambas inactivas). A los 10 ms, A tiene 1 solicitud en curso y B tiene 0, así que R2 va a B; B siempre vuelve a estar libre antes de la siguiente llegada, así que de R3 a R8 van todas a B |
| Resultado de menos conexiones | Cada lectura de la carta tarda 10 ms; el informe tarda 100 ms. Media (100 + 70) ÷ 8 ≈ 21 ms, peor lectura de la carta 10 ms |
| Por qué | El round robin cuenta solicitudes, no trabajo. Menos conexiones cuenta el trabajo en curso, que, según la ley de Little (en curso = tasa × tiempo), crece en la instancia que sea más lenta o esté más ocupada, así que las solicitudes nuevas se alejan de ella automáticamente |
El mismo efecto aparece siempre que los costos de las solicitudes varían mucho (búsquedas frente a consultas puntuales, exportaciones frente a lecturas) o que una instancia es más lenta que sus pares por un vecino ruidoso, una pausa de recolección de basura o una caché fría.
Menos conexiones necesita un recuento significativo. Con HTTP/2 o gRPC muchas solicitudes comparten una conexión, así que los balanceadores cuentan en su lugar las solicitudes pendientes; con conexiones WebSocket de larga duración, el recuento mide sesiones, no carga.
Una instancia recién arrancada tiene cero conexiones y puede verse inundada antes de que sus cachés estén calientes; muchos balanceadores ofrecen un periodo de arranque lento (slow start) que aumenta su parte gradualmente durante un minuto más o menos.
El poder de dos elecciones aleatorias
Si menos conexiones funciona tan bien, ¿por qué no elegir siempre la instancia menos cargada a nivel global? Porque en un sistema grande no existe una visión única y actual de la carga. Decenas de balanceadores de carga o miles de balanceadores en el lado del cliente ven cada uno solo sus propias solicitudes, o un informe de carga de hace unos segundos. Si todos eligen la instancia que parecía menos cargada, todos eligen la misma, que enseguida se ve desbordada, y luego todos pasan a la siguiente: una manada que persigue la carga por todo el pool.
La tesis doctoral de Michael Mitzenmacher (1996), publicada como The Power of Two Choices in Randomized Load Balancing (IEEE Transactions on Parallel and Distributed Systems, 2001) y basada en trabajos anteriores de Azar, Broder, Karlin y Upfal, analizó una alternativa sorprendentemente sencilla: elegir dos instancias al azar y enviar la solicitud a la menos cargada de las dos. En el modelo clásico de bolas en urnas, colocar n solicitudes en n servidores al azar da un servidor más cargado con unas log n ÷ log log n solicitudes; con dos elecciones aleatorias esto baja a unas log log n ÷ log 2, una mejora exponencial, mientras que una tercera elección añade muy poco más. El azar evita el efecto manada y la comparación evita las peores instancias.
El poder de dos elecciones aleatorias (power of two choices) es hoy la opción predeterminada o una opción estándar en proxies muy utilizados: el balanceador least-request de Envoy compara de forma predeterminada dos hosts elegidos al azar, y NGINX ofrece random two least_conn. Es una buena opción predeterminada para el balanceo en el lado del cliente en cualquier sistema con muchos balanceadores.
Hashing y afinidad
A veces lo que se busca es enviar las solicitudes relacionadas a la misma instancia: a un nodo de caché que ya tiene la carta de un restaurante, o a la instancia que mantiene una sesión WebSocket. Aplicar un hash a una clave (identificador del restaurante, identificador del usuario, IP de origen) para asignarla a una instancia lo consigue. Un simple hash mod N reasigna la mayoría de las claves cada vez que cambia N, lo que vacía todas las cachés en el peor momento, durante un escalado horizontal. El hashing consistente (presentado en la Sección 7.4) mueve solo alrededor de 1 ÷ N de las claves cuando una instancia entra o sale. Su punto débil son las claves calientes: el restaurante más popular a la hora del almuerzo cae en una sola instancia. Variantes como el hashing consistente con cargas acotadas limitan la parte de cada instancia y desvían el exceso a la siguiente instancia del anillo.
Comprobaciones de estado: actividad y preparación
Un balanceador de carga debe saber qué instancias pueden recibir tráfico. Una comprobación de estado (health check) activa sondea cada instancia periódicamente, por ejemplo GET /healthz cada cinco segundos, y la marca como caída tras unos cuantos fallos consecutivos y de nuevo como disponible tras unos cuantos éxitos. Las comprobaciones pasivas, a menudo llamadas detección de valores atípicos (outlier detection), observan el tráfico real y expulsan una instancia que devuelve, por ejemplo, cinco errores de servidor consecutivos. Las dos se complementan: las comprobaciones activas encuentran instancias que no reciben tráfico, y las pasivas reaccionan a fallos que una sonda trivial no ejercita.
Kubernetes hizo explícita una distinción importante. Una sonda de actividad (liveness probe) pregunta si el proceso está atascado sin posibilidad de recuperarse (en un interbloqueo, sin memoria en un bucle); si falla, la instancia se reinicia. Una sonda de preparación (readiness probe) pregunta si la instancia debe recibir tráfico en este momento; si falla, la instancia se retira del balanceador de carga pero sigue en ejecución, por ejemplo mientras calienta sus cachés al arrancar o mientras descarta carga. Una tercera, la sonda de arranque (startup probe), mantiene en suspenso las otras dos mientras arranca una aplicación lenta.
El error clásico es comprobar las dependencias compartidas en estas sondas. Si la sonda de actividad de cada instancia llama a la base de datos, una breve caída de la base de datos hace que fallen todas las sondas, el orquestador reinicia todas las instancias a la vez y la tormenta de reinicios (cachés frías, miles de conexiones nuevas) prolonga la caída mucho después de que la base de datos haya vuelto. Las comprobaciones de preparación que incluyen una dependencia compartida pueden igualmente marcar toda la flota como no preparada, convirtiendo errores parciales en una caída total. Mantén la sonda de actividad local y mínima; deja que la de preparación refleje la capacidad de la propia instancia para atender; y gestiona los fallos de las dependencias con los patrones de la Sección 9.4. Los balanceadores de carga se protegen del caso extremo fallando en abierto: un AWS Application Load Balancer enruta a todos los destinos si todos fallan sus comprobaciones de estado, y Envoy ignora el estado de salud cuando la proporción de hosts sanos cae por debajo de un umbral de pánico (50% de forma predeterminada), con el razonamiento de que enviar tráfico a instancias dudosas es mejor que no enviarlo a ninguna parte.
Drenaje de conexiones y apagado elegante
Las instancias salen del pool constantemente: cada despliegue las sustituye, el autoescalado las retira y la plataforma las mueve durante el mantenimiento. Si una instancia simplemente se mata, todas las solicitudes que estaba procesando fallan, y los clientes ven errores durante lo que debería ser un lanzamiento rutinario. El drenaje de conexiones (connection draining) (llamado deregistration delay en AWS) retira la instancia de la rotación del balanceador para que no reciba solicitudes nuevas, espera a que terminen las solicitudes que ya están en curso y solo entonces la deja detenerse.
La instancia debe colaborar. Al recibir su señal de apagado, debe fallar su comprobación de preparación, seguir atendiendo las solicitudes en curso, indicar a los clientes con conexiones keep-alive que vayan a otro sitio (una cabecera Connection: close en HTTP/1.1, una trama GOAWAY en HTTP/2), terminar o devolver el trabajo en segundo plano y salir antes de que acabe el periodo de gracia. En Kubernetes, retirar un pod del balanceador de carga y enviarle SIGTERM ocurren a la vez, así que todavía puede llegar una solicitud justo después de la señal; una breve espera previa a la parada (pre-stop) de unos segundos cubre esa carrera. El periodo de gracia predeterminado es de 30 segundos, después de los cuales se mata el proceso. Las solicitudes de larga duración (subidas grandes, respuestas en streaming, WebSockets) necesitan un periodo de gracia más largo o un protocolo con el que los clientes se vuelvan a conectar en otro sitio sin perder trabajo.
Apagado elegante en cinco pasos
Las sesiones persistentes y sus problemas
Las aplicaciones web más antiguas guardaban la sesión de cada usuario (quién ha iniciado sesión, qué hay en el carrito) en la memoria del servidor que la había creado. Detrás de un balanceador de carga, esto solo funciona si todas las solicitudes de un usuario vuelven a ese servidor, así que los balanceadores ofrecen sesiones persistentes (sticky sessions) (afinidad de sesión), normalmente mediante una cookie que identifica la instancia. La persistencia es una forma rápida de poner una aplicación con estado detrás de un balanceador, y tiene un uso legítimo como pista de rendimiento, por ejemplo para mantener a un usuario en una instancia cuya caché local ya contiene sus datos.
Como mecanismo de corrección, causa problemas. La carga se vuelve desigual, porque unos pocos usuarios intensivos o una gran oficina detrás de una sola dirección IP se quedan fijados a una instancia sea cual sea su carga. Cuando una instancia falla, sus usuarios pierden sus sesiones: los carritos desaparecen y las personas ven cerrada su sesión. Las reducciones y cada despliegue hacen lo mismo salvo que se drenen las sesiones, lo que puede tardar tanto como la sesión más larga. Las instancias nuevas que añade el autoescalado solo reciben usuarios nuevos, así que alivian despacio a las instancias sobrecargadas. Y el sistema ya no es sin estado en el sentido de la Sección 9.1, así que todos estos problemas reaparecen en el failover entre zonas o regiones.
Externalizar el estado de sesión
El remedio es sacar el estado de sesión de la instancia, para que cualquier instancia pueda atender cualquier solicitud. Hay tres opciones principales, que a menudo se combinan. Un token en el lado del cliente lleva el estado con cada solicitud: una cookie firmada (y, si hace falta, cifrada) o un token como un JWT que contiene la identidad del usuario y algunos datos. Los servidores no necesitan ningún almacén, pero los tokens deben ser pequeños, no se pueden revocar fácilmente antes de que caduquen y deben protegerse contra la manipulación y el robo (Sección 8.3). Un almacén de sesiones compartido, normalmente Redis o Memcached, guarda las sesiones en un almacén externo rápido, indexadas por un identificador de sesión que va en la cookie; admite un estado más grande y el cierre de sesión inmediato, a costa de una llamada de red por solicitud y de una dependencia que a su vez debe tener alta disponibilidad. Una base de datos es adecuada para el estado que debe sobrevivir a cualquier cosa, como un carrito que el usuario espera encontrar mañana, que en realidad son datos de negocio y no datos de sesión.
Un reparto práctico para la plataforma de reparto de comida: la identidad, en un token firmado de corta duración; el carrito, en la base de datos del servicio de pedidos (los usuarios pasan del teléfono a la computadora portátil); y el estado transitorio de la interfaz, en el cliente. Ninguna instancia guarda nada que necesite una solicitud posterior, así que el balanceador de carga puede usar un balanceo por menos solicitudes sin afinidad, y las instancias se pueden añadir, retirar y sustituir a voluntad.
Balanceo de carga global: DNS y anycast
Cuando un sistema se ejecuta en varias regiones, algo debe enviar a cada usuario a una región adecuada: la región sana más cercana o la región que tiene sus datos. El balanceo de carga global suele hacerse de una de dos formas, que a menudo se combinan.
El balanceo global de servidores basado en DNS usa un servidor de nombres autoritativo que responde al mismo nombre con direcciones distintas según el origen de la consulta, la salud de cada región y unos pesos configurados: a un usuario de Lisboa se le da la dirección de la región de la UE, y a uno de Ohio, la de la región de EE. UU. No necesita ninguna red especial, pero es tosco y lento en reaccionar. Los resolutores guardan las respuestas en caché durante al menos el tiempo de vida (TTL) del registro (a menudo de 30 a 300 segundos) y a veces más, así que, después de que falle una región, algunos usuarios siguen llegando a ella durante minutos. El servidor de nombres ve la ubicación del resolutor y no la del usuario, aunque la extensión EDNS Client Subnet (RFC 7871) permite que los resolutores transmitan parte de la dirección del cliente.
Con anycast, la misma dirección IP se anuncia desde muchos sitios mediante el protocolo de enrutamiento de internet (BGP), y los paquetes de cada usuario se entregan al sitio que esté más cerca en términos de enrutamiento. El failover consiste en retirar el anuncio de un sitio que ha fallado, lo que surte efecto enseguida sin esperar a las cachés de DNS. Anycast se usa desde hace mucho en los servicios raíz y de resolución de DNS; las CDN y los balanceadores de carga globales de los grandes proveedores de nube lo usan para llevar a los usuarios a un sitio de borde cercano, donde proxies de capa 7 terminan la conexión y reenvían las solicitudes por la red del proveedor a una región sana. El diseño multirregión, la ubicación de los datos y el failover son el tema de la Sección 10.6.
Balanceo de carga global basado en DNS y con anycast
Comprueba lo que has entendido
¿Por qué un servidor gRPC recién añadido detrás de un balanceador de carga de capa 4 podría no recibir tráfico?
El balanceo de capa 4 elige un backend por conexión, y los clientes gRPC mantienen una sola conexión HTTP/2 de larga duración, así que los clientes existentes nunca le envían solicitudes hasta que se vuelven a conectar.
¿Qué diferencia de efecto hay entre fallar una sonda de actividad y fallar una sonda de preparación?
Fallar la de actividad hace que el orquestador reinicie la instancia; fallar la de preparación solo la retira del balanceador de carga hasta que vuelva a superarla.
¿Por qué funcionan mal muchos balanceadores de carga independientes que eligen la instancia menos cargada?
Actúan sobre la misma visión desfasada y todos eligen la misma instancia, que se sobrecarga por turnos; elegir la mejor de dos instancias aleatorias evita este efecto manada.
Da dos problemas que causa guardar las sesiones en la memoria de la instancia con sesiones persistentes.
Los usuarios pierden sus sesiones cuando la instancia falla o se sustituye, y la carga se vuelve desigual porque los usuarios intensivos se quedan fijados a una instancia.
Fuentes y lecturas recomendadas
¿Tienes una pregunta sobre esta sección? ArchitectBot, el asistente de estudio con IA del curso, responde primero a partir del curso.
Pregunta: “Ejecutamos ocho instancias detrás de un balanceador de carga con sesiones persistentes y perdemos los carritos de los usuarios en cada despliegue. ¿Cómo pasamos a instancias sin estado de forma segura?”