Balanceo de carga#

Angie distribuye las solicitudes de los clientes entre un grupo de servidores upstream descrito por un bloque upstream. Qué servidor atiende una solicitud dada lo decide el método de balanceo del grupo.

Esta guía cubre el balanceo de HTTP, que se configura en el módulo HTTP Upstream. El balanceo de sesiones TCP y UDP funciona de la misma manera y se configura en el módulo Stream Upstream; las diferencias se indican donde son relevantes.

Un grupo usa exactamente un método de balanceo. Si en un bloque se indica más de uno, se aplica el último y Angie registra load balancing method redefined; un bloque que no indica ninguno usa Round-robin ponderado.

Elección de un método#

El método determina cómo elige Angie un servidor para cada solicitud, y cada método acepta su propio conjunto de parámetros de server. Un parámetro que un método no admite no se ignora: Angie se niega a arrancar e informa balancing method does not support parameter. Consulte esta tabla antes de combinar un método con weight, slow_start o backup.

Método

Distribuye las solicitudes por

Nivel

weight

slow_start

backup

Round-robin ponderado

Posición en una rotación ponderada. Es el valor predeterminado; no requiere directiva.

L4, L7

hash

Hash de una clave que usted elige, como un URI o una cabecera.

L4, L7

ip_hash

Hash de la dirección del cliente.

L7

least_conn

Menor número de conexiones activas por unidad de peso.

L4, L7

random

Probabilidad, proporcional al peso.

L4, L7

least_time

Probabilidad, inversamente proporcional al tiempo medio de respuesta.

L4, L7

feedback (PRO)

Probabilidad, proporcional a un valor que informan los servidores.

L4, L7

Todos los métodos anteriores están disponibles en Angie, excepto feedback, que requiere Angie PRO. ip_hash no tiene equivalente en Stream; use en su lugar hash con $remote_addr.

Métodos de balanceo#

Round-robin ponderado#

El round-robin es el método predeterminado: Angie lo usa siempre que un grupo no indica ningún otro método, y no tiene una directiva propia. Angie recorre por turnos los servidores del grupo y da a cada uno una parte de la rotación proporcional a su weight:

upstream backend {
    zone backend 1m;
    server backend1.example.com weight=5;
    server backend2.example.com;
    server backend3.example.com;
}

De cada siete solicitudes, cinco van a backend1.example.com y una a cada uno de los demás. La distribución es uniforme: las solicitudes al servidor con mayor peso se reparten a lo largo de la rotación en lugar de enviarse todas juntas, de modo que el grupo nunca recibe cinco solicitudes consecutivas para un servidor seguidas de dos para el resto.

El round-robin también sirve como alternativa de reserva para otros métodos. Cuando hash, ip_hash o random no logran decidirse por un servidor utilizable, delegan la elección al round-robin.

hash#

El método hash envía al mismo servidor todas las solicitudes cuyas claves tienen el mismo hash. Resulta útil cuando los servidores del grupo almacenan respuestas en caché por sí mismos, como los proxies de caché o los nodos de memcached. Mientras la composición del grupo no cambie, las solicitudes de un URI dado llegan siempre al mismo servidor, de modo que su respuesta se guarda en ese único servidor y no en todos los del grupo.

upstream backend {
    zone backend 1m;
    hash $request_uri consistent;
    server backend1.example.com;
    server backend2.example.com;
}

La clave puede ser cualquier cadena formada por variables. Los pesos funcionan dando a un servidor más pesado una porción proporcionalmente mayor del espacio de claves.

Sin consistent, Angie asigna el hash de la clave a un rango tan largo como el peso total del grupo, en el que cada servidor ocupa un segmento tan largo como su peso. Añadir o quitar un servidor cambia ese total y, por tanto, reasigna muchas claves además de las del servidor añadido o quitado: sus respuestas en caché quedan en servidores que ya no reciben solicitudes para ellas. Con consistent, Angie coloca los servidores en un anillo ketama en su lugar, y al quitar un servidor solo se reasignan las claves que ese servidor tenía.

Nota

Las posiciones de un servidor en el anillo se calculan a partir de su nombre tal como aparece en la directiva server, no de las direcciones a las que ese nombre se resuelve. Todas las direcciones de un mismo nombre comparten esas posiciones, así que el nombre ocupa del anillo tanto como un único servidor del mismo peso. Cuando una clave cae en una de las posiciones del nombre, Angie elige una de sus direcciones mediante round-robin.

Sin consistent, cada dirección cuenta como un servidor distinto con su propio peso, y el hash se asigna al peso total de todas las direcciones. Por eso, un nombre que se resuelve a varias direcciones recibe una parte proporcional al número de esas direcciones.

ip_hash#

El método ip_hash usa como clave la dirección del cliente: los tres primeros octetos de una dirección IPv4, o la dirección IPv6 completa. Las solicitudes de un mismo cliente llegan a un mismo servidor mientras ese servidor esté disponible.

No tiene un modo de hash consistente, por lo que cambiar el conjunto de servidores puede redirigir a muchos clientes a otros servidores. Para retirar un servidor del servicio conservando el resto de la asignación, márquelo con down en lugar de borrar su línea:

upstream backend {
    zone backend 1m;
    ip_hash;
    server backend1.example.com;
    server backend2.example.com down;
    server backend3.example.com;
}

least_conn#

El método least_conn elige el servidor con menos conexiones activas por unidad de peso: minimiza la proporción entre conexiones y peso, no el número absoluto. Por eso, un servidor con weight=2 y 15 conexiones se prefiere frente a uno con weight=1 y 10 conexiones. Cuando varios servidores empatan, se prueban por turnos mediante round-robin ponderado.

Solo cuentan las conexiones que en ese momento están transmitiendo una solicitud. Las conexiones keepalive inactivas no cuentan.

Úselo cuando las solicitudes difieren mucho en el tiempo que ocupan a un servidor: descargas grandes, long polling, WebSocket. El round-robin envía a cada servidor el mismo número de solicitudes por unidad de peso, pero ese número dice poco sobre la carga cuando unas solicitudes retienen un servidor durante milisegundos y otras durante minutos; least_conn cuenta las solicitudes que un servidor está atendiendo en este momento. Si lo que difiere es la velocidad de los servidores, use least_time.

random#

El método random elige un servidor al azar, en proporción a su peso. En un número grande de solicitudes, la distribución coincide con los pesos.

El parámetro two elige dos servidores al azar y luego toma el que de los dos tenga menos conexiones activas por unidad de peso:

upstream backend {
    zone backend 1m;
    random two;
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com;
}

Esto importa cuando varios balanceadores atienden a los mismos servidores sin compartir estado. Si cada balanceador elige por su cuenta el único servidor menos cargado, todos terminan enviando tráfico al mismo objetivo; elegir el mejor de dos candidatos aleatorios reparte la carga en su lugar. Con un solo balanceador, least_conn es la opción más simple.

Nota

random two least_conn se acepta por compatibilidad y se comporta exactamente igual que random two; comparar conexiones activas es el único modo que tiene two.

least_time#

El método least_time favorece a los servidores que responden rápido. Su modo define qué se mide: header es el tiempo hasta recibir la cabecera de la respuesta, y last_byte, el tiempo hasta recibir la respuesta completa.

Un grupo cuyos servidores se comparan por el tiempo hasta la cabecera de la respuesta:

upstream backend {
    zone backend 1m;
    least_time header;
    server backend1.example.com;
    server backend2.example.com;
}

La medición es una media móvil ponderada exponencialmente, de modo que una sola respuesta lenta no desplaza mucho la puntuación de un servidor. La directiva response_time_factor, o el parámetro factor, determina cuánto peso conserva el historial acumulado frente a cada nueva medición: un factor alto reacciona despacio, uno bajo olvida rápido.

Antes de elegir este método conviene conocer dos de sus propiedades.

No elige simplemente el servidor más rápido. La probabilidad de que un servidor reciba la solicitud es inversamente proporcional a su tiempo medio de respuesta. Incluso un servidor constantemente lento conserva una pequeña parte: aproximadamente un uno por ciento de lo que recibe un servidor promedio, es decir, alrededor de una solicitud de cada 100 x N para un grupo de N servidores. Esto es intencional: un servidor que no recibiera nada nunca produciría una nueva medición, y nunca se podría comprobar que se ha recuperado.

Rechaza weight. Un grupo que combina least_time con weight= en cualquier servidor no arrancará. El tiempo de respuesta ya refleja la carga que absorbe un servidor, así que no queda nada que un peso pueda expresar.

En Stream, least_time acepta un conjunto distinto de modos: connect (el tiempo para establecer una conexión con el servidor), first_byte (el tiempo hasta recibir el primer byte de datos del servidor) y last_byte (el tiempo hasta que termina la sesión); header no está disponible.

feedback#

El método feedback (PRO) permite que los propios servidores indiquen cuánto trabajo quieren recibir. Angie lee un valor de cada respuesta (normalmente una cabecera) y asigna a un servidor una parte de las solicitudes proporcional a ese valor, promediándolo de la misma forma en que least_time promedia el tiempo de respuesta.

upstream backend {
    zone backend 1m;
    feedback $upstream_http_x_capacity;
    server backend1.example.com;
    server backend2.example.com;
}

Advertencia

El valor se interpreta en el sentido esperado para la capacidad disponible: cuanto mayor es el valor reportado, mayor es la parte que recibe el servidor. Si su métrica aumenta a medida que el servidor se satura (carga de CPU, profundidad de la cola), añada el parámetro inverse, o de lo contrario enviará la mayor parte del tráfico al servidor más cargado.

El parámetro account selecciona qué respuestas alimentan el promedio, lo que permite basar el balanceo en las respuestas de upstream_probe (PRO) en lugar de en el tráfico de los clientes.

Pesos de los servidores y reparto del tráfico#

weight no significa lo mismo para todos los métodos, y solo en algunos de ellos la parte de tráfico de un servidor es igual a su peso dividido entre la suma de todos los pesos:

Método

Qué hace weight

round-robin, random

Define la parte directamente. La parte es igual al peso dividido entre el peso total.

hash, ip_hash

Define la parte del espacio de claves. El tráfico coincide con los pesos solo si las claves mismas están distribuidas de forma uniforme; las direcciones reales de los clientes y los URI normalmente no lo están.

least_conn

Divide el número de conexiones que se compara. Un servidor con mayor peso termina con un número proporcionalmente mayor de conexiones simultáneas, no de solicitudes.

least_time

Nada: el parámetro se rechaza al arrancar.

feedback

Multiplica el valor que reporta el servidor. El peso es solo uno de los dos factores, por lo que la parte no se puede predecir a partir del peso por sí solo.

En cuanto entran en juego max_conns, slow_start, max_fails, down o los servidores de respaldo, ningún método distribuye el tráfico estrictamente según el peso.

Fallos y recuperación#

Comprobaciones pasivas#

Angie evalúa a un servidor por el resultado de las solicitudes que le envía. Si un intento cumple una condición de reintento y no se ha agotado el límite de intentos, Angie puede pasar la solicitud a otro servidor. La directiva proxy_next_upstream y sus equivalentes definen esas condiciones; proxy_next_upstream_tries y proxy_next_upstream_timeout limitan el número y la duración de los intentos.

Un número de intentos fallidos igual a max_fails dentro de fail_timeout marca un servidor como no disponible durante ese mismo período, después del cual se vuelve a intentar. Los valores predeterminados son un intento y diez segundos. Lo que cuenta como intento fallido lo definen proxy_next_upstream y sus equivalentes.

Establecer max_fails=0 desactiva la comprobación para ese servidor: nunca se marca como no disponible.

Nota

Por debajo del umbral de max_fails, un fallo aislado también reduce la porción del servidor, que se recupera de forma gradual. Sin slow_start, Angie reduce el peso efectivo que usan round-robin y least_conn, y después lo restaura a lo largo de las solicitudes siguientes. Con slow_start, cada fallo hace retroceder al servidor en la rampa temporal que emplean todos los métodos compatibles con ese parámetro. Ambos comportamientos requieren que max_fails sea mayor que uno: con el valor predeterminado de uno, el primer fallo marca el servidor como no disponible, por lo que no existe un estado intermedio.

Comprobaciones activas#

Las comprobaciones pasivas se enteran del estado de un servidor solo por las solicitudes de los clientes: un fallo se detecta cuando las solicitudes de los clientes a ese servidor ya han fallado, y una recuperación, solo cuando se le vuelve a enviar una solicitud de un cliente. Las comprobaciones activas, disponibles en Angie PRO, contactan con los servidores según una planificación, con independencia del tráfico de los clientes, y detectan tanto el fallo como la recuperación sin gastar solicitudes de clientes en ninguno de los dos casos.

Una comprobación se configura con la directiva upstream_probe (PRO) en el mismo bloque location que pasa las solicitudes al grupo; el grupo, a su vez, necesita una zona de memoria compartida:

upstream backend {
    zone backend 1m;
    server backend1.example.com;
    server backend2.example.com;
}

map $upstream_status $good {
    200     "1";
}

server {
    listen 80;

    location / {
        proxy_pass http://backend;
        upstream_probe backend_probe uri=/health interval=5s
                       test=$good fails=3 passes=2;
    }
}

Cada cinco segundos, Angie solicita /health a cada servidor del grupo. Tres comprobaciones fallidas seguidas marcan al servidor como no saludable; dos comprobaciones superadas seguidas lo devuelven al servicio. Sin el parámetro test, una comprobación falla solo cuando una solicitud de un cliente en este location contaría como un intento fallido. De forma predeterminada, proxy_next_upstream cuenta únicamente un error o un tiempo de espera agotado, así que una respuesta 500 o 503 no hace fallar la comprobación. Aquí, test=$good da por superada la comprobación solo si el servidor responde con 200: para cualquier otro estado, map deja la variable vacía.

Las respuestas de las comprobaciones también pueden alimentar el método feedback mediante su parámetro account.

Un servidor que se detecta como no saludable queda excluido de la selección para todos los métodos de balanceo. Tras una recarga de la configuración, las comprobaciones empiezan de nuevo. De forma predeterminada, un servidor sigue recibiendo solicitudes sin esperar a la primera comprobación posterior a la recarga. Si upstream_probe tiene el parámetro essential, el servidor no recibe solicitudes hasta que la comprobación lo encuentra saludable por primera vez (en este ejemplo, tras dos comprobaciones superadas seguidas); añadir persistent, que solo funciona junto con essential, elimina esta espera para los servidores que estaban saludables antes de la recarga, porque su indicador de estado se conserva en la zona (consulte Estado compartido entre procesos de trabajo).

Servidores de respaldo#

Los servidores marcados con backup se mantienen en reserva:

upstream backend {
    zone backend 1m;
    server backend1.example.com;
    server backend2.example.com;

    server backup1.example.com backup;
}

Toda solicitud comienza por los servidores principales y llega al grupo de respaldo solo cuando ningún servidor principal puede atenderla. No existe un modo de conmutación por error persistente del que haya que volver: en cuanto un servidor principal vuelve a pasar su comprobación de estado, la siguiente solicitud lo utiliza.

Angie PRO puede invertir este comportamiento con el parámetro permanent de backup_switch (PRO), que sigue enviando solicitudes al grupo que las atendió por última vez. Sin un argumento de tiempo, el cambio nunca revierte por sí solo; con permanent=time, Angie envía una solicitud de vuelta al grupo principal tras ese intervalo para comprobar si se ha recuperado.

El parámetro backup es rechazado por hash, ip_hash y random.

Reincorporación de un servidor al servicio#

El parámetro slow_start hace que un servidor recuperado recupere su peso completo de forma gradual durante un período, en lugar de restaurarlo de inmediato, lo que evita que una caché fría o un proceso recién iniciado reciba tráfico a máxima velocidad desde el principio:

server backend1.example.com slow_start=30s;

Se aplica sobre todo después de que un servidor ha sido marcado como no disponible y se ha recuperado; un fallo aislado también hace retroceder al servidor en la misma rampa (consulte Fallos y recuperación). Solo funciona con los métodos marcados en la columna slow_start de Elección de un método. A diferencia de otras implementaciones, no requiere la directiva zone.

Para retirar un servidor de la rotación de forma deliberada, use down; para dejar de enviarle tráfico nuevo mientras se completan las sesiones ya vinculadas, use drain.

Estado compartido entre procesos de trabajo#

El balanceo solo es coherente en toda una instancia de Angie si los procesos de trabajo comparten su visión del grupo. La directiva zone les proporciona esa visión compartida:

upstream backend {
    zone backend 1m;
    server backend1.example.com;
    server backend2.example.com;
}

Sin ella, cada proceso de trabajo mantiene su propia copia del estado en tiempo de ejecución del grupo (contadores de fallos, número de conexiones activas, posición en la rotación round-robin, promedios de tiempo de respuesta) y balancea de forma independiente de los demás. Con N procesos de trabajo, en la práctica se ejecutan N balanceadores sobre los mismos servidores: un proceso puede tener un servidor marcado como no disponible mientras el resto le sigue enviando solicitudes, y un límite de max_conns se aplica por proceso, lo que permite hasta N veces más conexiones de las configuradas.

Una zona también es lo que hace visible al grupo para las métricas de upstream, y es necesaria para los parámetros resolve y service de la directiva server.

Nota

Una recarga de la configuración vuelve a crear la zona, cambie o no size: los contadores, el estado de las comprobaciones pasivas y el historial de balanceo acumulado parten de cero. Se conservan dos cosas: las direcciones resueltas para los servidores con resolve y el indicador de estado en el que se apoyan las comprobaciones activas con el parámetro persistent (consulte Comprobaciones activas).

Persistencia de sesión y controles relacionados#

El balanceo decide adónde va una solicitud. Dos directivas limitan esa decisión:

sticky

Vincula la sesión de un cliente al servidor que la atendió primero, identificado mediante una cookie, un valor de ruta o, con learn, un valor que Angie observa en el tráfico. Mientras dura la sesión, esta vinculación prevalece sobre el método de balanceo.

queue (PRO)

Retiene brevemente una solicitud cuando ningún servidor puede atenderla, en lugar de rechazarla de inmediato. Es útil cuando se alcanza max_conns durante picos de carga breves.

La directiva keepalive no influye en qué servidor se elige: mantiene abiertas conexiones inactivas con los servidores, de modo que una solicitud a un servidor ya elegido reutilice una de ellas en lugar de abrir una nueva. El número de estas conexiones está limitado por proceso de trabajo, no en total.

Advertencia

Las directivas sticky, keepalive y queue deben aparecer después de la directiva que establece el método de balanceo; de lo contrario, no tienen ningún efecto.