¿Cuál es un método típico para escalar un equilibrador de carga de software?


22

A menudo veo arquitecturas de aplicaciones web con un SLB / proxy inverso frente a un montón de servidores de aplicaciones.

¿Qué sucede cuando la cantidad de conexiones a la SLB requiere demasiados recursos para que una sola SLB se maneje de manera efectiva? Para un ejemplo concreto pero exagerado, considere 2 millones de conexiones HTTP persistentes. Claramente, un solo SLB no puede manejar esto.

¿Cuál es la configuración recomendada para la ampliación a cabo un SLB?

¿Es típico crear un grupo / clúster de LB? Si es así, ¿cómo se distribuye la carga del cliente entre el grupo de LB?


z8000, ¿puede decir qué software equilibrador de carga está utilizando? Además, si es posible, qué algoritmo / protocolo utiliza para el equilibrio de carga.
Martin

No tengo preferencia Actualicé la pregunta para que sea más clara.
z8000

No me queda claro por qué un equilibrador de carga intrínsecamente no puede manejar 2 millones de conexiones HTTP persistentes.
womble

Respuestas:


10

Los equilibradores de carga no pueden ser escalados fácilmente por otros equilibradores de carga, ya que inherentemente habrá un solo equilibrador de carga en la cadena en algún lugar que mantenga las conexiones. Dicho esto, los equilibradores como LVS o HAProxy tienen una capacidad absurda en el rango de Gbps. Una vez que supere las capacidades de un solo equilibrador de carga (software, hardware, lo que sea), deberá pasar a otras técnicas, como el DNS round robin.


¡Correcto! Tener el único LB es el "problema". Estoy de acuerdo en que el rendimiento no sería un problema en general. Pero me preocupan otros recursos como la RAM, que en mi caso es limitada. Hay pocas conexiones que se pueden alojar en un único SLB antes de que se agote la RAM.
z8000

HAProxy puede manejar aproximadamente 20k-60k sesiones activas por GB de RAM. Creo que LVS puede hacer mucho más, ya que los datos de sesión retenidos son más pequeños. Si se queda sin RAM, actualícela o cree otro equilibrador de carga con un sistema DNS de operación por turnos.
Hyppy

1
"Los equilibradores de carga no pueden ser escalados fácilmente por otros equilibradores de carga". En realidad, un solo equilibrador de carga L4 basado en ASIC a menudo se puede colocar frente a un par de equilibradores de carga basados ​​en HTTP L7 con excelentes resultados. El mismo principio básico se aplica a las implementaciones solo de software, por ejemplo, Linux LVS frente a nignx.
Jesper M

19

OK, ya hay una respuesta aceptada, pero hay algo que agregar. Las formas "clásicas" más comunes de escalar el nivel del equilibrador de carga son (sin ningún orden en particular):

  • DNS Round Robin para publicitar múltiples direcciones IP para el dominio. Para cada dirección IP, implemente un par de servidores de alta disponibilidad (2 servidores que cooperan para mantener una dirección IP funcionando en todo momento). Cada IP corresponde a un clúster de equilibrador de carga, ya sea utilizando dispositivos o servidores con software de equilibrio de carga. Escale horizontalmente agregando más pares de equilibrador de carga según sea necesario.

  • Ajustes de enrutamiento o firewall para distribuir la carga a múltiples equilibradores de carga. Haga que el enrutador frontal o el cortafuegos frontal distribuyan las conexiones entrantes a varias direcciones IP (cada una de las cuales representa un par de equilibrador de carga) haciendo un hash de la dirección IP de origen , teniendo múltiples rutas de igual costo a los equilibradores de carga, o similar.

  • Una capa de equilibradores de carga de nivel IP frente a una capa de equilibradores de carga de nivel HTTP . El equilibrio de carga de la capa IP se puede implementar en ASIC / silicio, y puede ser muy rápido para algunas cosas. Por lo tanto, un solo par de equilibrador de carga IP a menudo puede 'mantenerse' con varios equilibradores de carga de nivel HTTP / HTTPS, y proporcionar niveles de rendimiento de varios gigabits mientras mantiene la arquitectura agradable y simple.

Profundizar completamente en las diferentes formas de hacer lo anterior requeriría una respuesta muy larga. Pero en general, no es tan difícil escalar el nivel del equilibrador de carga , es mucho más difícil escalar el nivel del servidor de aplicaciones y especialmente el nivel de la base de datos.

Ya sea que elija un factor de forma de dispositivo (F5, Cisco, A10) o un servidor genérico (software Windows / Linux +) no importa tanto. Las principales consideraciones al escalar la capa de equilibrador de carga son:

  • Lleno de estado versus apátrida. ¿Necesitas sesiones adhesivas o puedes vivir sin ellas? No mantener el estado hace que todo sea más simple.
  • 'Hardware' (ASIC) versus 'software' (servidores de uso general) para el equilibrio de carga. Cada uno tiene sus pros y sus contras, consulte la documentación general de HAProxy vinculada anteriormente.
  • Equilibrio de carga L3 / 4 (IP / TCP / IP) versus equilibrio de carga L7 (HTTP) . Una vez más, pros y contras, el documento HAProxy proporciona una buena visión general.
  • Terminación SSL , donde, en los nodos web o en el equilibrador de carga.

En general, no necesita preocuparse por esto antes de que su sitio web sea muy grande: un único servidor moderno con fx nginx manejará decenas de miles de solicitudes HTTP simples por segundo. Así que no hagas una optimización prematura, no lidies con esto antes de que tengas que hacerlo.


En realidad, no necesita que cada dirección IP esté altamente disponible utilizando DNS RR. Los navegadores, en general, recurrirán a otra IP si está disponible cuando no puedan conectarse. Pero si tiene servicios web públicos, necesitará HA para cada dirección IP, ya que muchas bibliotecas de servicios web no manejarán la conmutación por error a otras IP automáticamente.
rmalayter

9

La clave para escalar una capa de equilibrio de carga HTTP es agregar primero otra capa de equilibrio de carga de nivel inferior (IP o TCP). Esta capa se puede construir completamente con software de código abierto, aunque obtendrá mejores resultados si tiene enrutadores modernos.

Los flujos (sesiones TCP) se deben codificar utilizando encabezados como los puertos IP y TCP de origen / destino, para decidir a qué interfaz van. También necesita un mecanismo para asegurarse de que cuando una interfaz muere, deja de acostumbrarse.

Hay varias estrategias, voy a describir un par que he usado en producción en sitios que sirven a millones de usuarios, para que pueda entender la idea. Sería demasiado largo para explicar todo en detalle, pero espero que esta respuesta le brinde suficiente información / consejos para comenzar. Para implementar estas soluciones, necesitará a alguien que conozca realmente las redes.

Es cierto que lo que estoy describiendo aquí es mucho más difícil de implementar que lo que se describe en otras respuestas, pero este es realmente el estado del arte si tiene un sitio web de alto tráfico con grandes problemas de escalabilidad y requisitos de disponibilidad superiores al 99,9% . Siempre que ya tenga un ingeniero de redes a bordo, cuesta menos configurarlo y ejecutarlo (tanto en capex como en opex) que los dispositivos balanceadores de carga, y se puede ampliar aún más sin casi ningún costo adicional (en comparación con la compra de uno nuevo, incluso más aparato costoso cuando superas tu modelo actual).

Primera estrategia: con un firewall

Presumiblemente tiene un par de enrutadores en los que están conectados los enlaces ascendentes de su ISP. Su ISP proporciona 2 enlaces (activo / pasivo, usando VRRP). En sus enrutadores, también usa VRRP y dirige el tráfico que va a su red pública a un firewall. Los cortafuegos ( FW 1y más FW 2abajo) también son activos / pasivos y filtrarán el tráfico y enviarán cada flujo a un servidor frontend (sus equilibradores de carga HTTP FE 1y más FE 2abajo).

      + -------------- + + -------------- +
      El | ISP router A | El | ISP router B |
      + -------------- + + -------------- +
             El | El |
           == # ====================== # == (red pública)
             El | El |
      + --------------- + + --------------- +
      El | Su enrutador A | El | Su enrutador B |
      + --------------- + + --------------- +
             El | El |
           == # ===== # ========== # ===== # == (red privada RFC 1918)
             El | El | El | El |
       + ------ + + ------ + + ------ + + ------ +
       El | FW 1 | El | FE 1 | El | FE 2 | El | FW 2 |
       + ------ + + ------ + + ------ + + ------ +

El objetivo es tener un flujo como este:

  1. El ISP dirige el tráfico que va a sus IP a su enrutador activo.
  2. Sus enrutadores enrutan el tráfico a un VIP que utiliza una dirección RFC 1918 . Este VIP es propiedad del firewall activo, al igual que VRRP. Si usa OpenBSD para sus necesidades de firewall, puede usar CARP , una alternativa sin patente a VRRP / HSRP.
  3. Su firewall aplica el filtro (por ejemplo, "solo permite que 80 / tcp y 443 / tcp vayan a esta dirección IP en particular").
  4. Su firewall también actúa como un enrutador y reenvía los paquetes a un frontend saludable.
  5. Su interfaz termina la conexión TCP.

Ahora la magia ocurre en los pasos 4 y 5, así que veamos con más detalles lo que hacen.

Su cortafuegos conoce la lista de interfaces ( FE 1y FE 2), y seleccionará una de ellas en función de un aspecto particular del flujo (p. Ej., Mediante el hash de la IP de origen y el puerto, entre otros encabezados). Pero también debe asegurarse de que reenvíe el tráfico a una interfaz saludable, de lo contrario, bloqueará el tráfico. Si usa OpenBSD, por ejemplo, puede usar relayd. Quérelayddoes es simple: verifica el estado de todas sus interfaces (por ejemplo, enviándoles una solicitud HTTP de sonda), y cada vez que una interfaz está en buen estado, la agrega a una tabla que el firewall usa para seleccionar el siguiente salto de los paquetes de un flujo dado . Si un frontend falla las comprobaciones de estado, se elimina de la tabla y ya no se envían paquetes. Al reenviar un paquete a un frontend, todo lo que hace el firewall es intercambiar la dirección MAC de destino del paquete para que sea la del frontend elegido.

En el paso 5, el equilibrador de carga recibe los paquetes del usuario (ya sea Varnish, nginx o lo que sea). En este punto, el paquete todavía está destinado a su dirección IP pública, por lo que debe alias sus VIP (s) en la interfaz de bucle invertido. Esto se llama DSR (Direct Server Return), porque sus interfaces terminan la conexión TCP y el cortafuegos intermedio solo ve tráfico simple (solo paquetes entrantes). Su enrutador enrutará los paquetes salientes directamente de regreso a los enrutadores del ISP. Esto es especialmente bueno para el tráfico HTTP porque las solicitudes tienden a ser más pequeñas que las respuestas, a veces significativamente. Para que quede claro: esto no es algo específico de OpenBSD y se usa ampliamente en sitios web de alto tráfico.

Gotchas:

  • Los usuarios finales se conectarán directamente a sus servidores frontend porque usted usa DSR. Tal vez ya era el caso, pero si no fuera así, debe asegurarse de que estén adecuadamente asegurados.
  • Si usa OpenBSD, tenga en cuenta que el núcleo tiene un solo subproceso, por lo que el rendimiento de un solo núcleo de CPU limitará el rendimiento de un firewall. Puede ser un problema dependiendo de su tipo de NIC y la tasa de paquetes que está viendo. Hay formas de resolver este problema (más sobre esto a continuación).

Segunda estrategia: sin firewall

Esta estrategia es más eficiente pero más difícil de configurar porque depende más de los detalles de los enrutadores que tiene. La idea es evitar el firewall anterior y hacer que los enrutadores hagan todo el trabajo que los firewalls estaban haciendo.

Necesitará enrutadores que admitan ACL L3 / L4 por puerto, BGP y ECMP , y enrutamiento basado en políticas (PBR). Solo los enrutadores de alta gama admiten estas características, y a menudo tienen tarifas de licencia adicionales para usar BGP. Esto suele ser aún más barato que los equilibradores de carga de hardware, y también es mucho más fácil de escalar. Lo bueno de estos enrutadores de gama alta es que tienden a ser de velocidad de línea (p. Ej., Siempre pueden maximizar el enlace, incluso en interfaces de 10 GbE, porque todas las decisiones que toman las toman los ASIC en hardware).

En los puertos en los que tiene sus enlaces ascendentes de ISP, aplique la ACL que solía estar en el firewall (por ejemplo, "solo permita que 80 / tcp y 443 / tcp vayan a esta dirección IP en particular"). Luego, haga que cada una de sus interfaces mantenga una sesión BGP con su enrutador. Puede usar el excelente OpenBGPD (si sus interfaces están en OpenBSD) o Quagga . Su enrutador ECMP el tráfico a las interfaces que están en buen estado (porque mantienen sus sesiones de BGP). El enrutador también enrutará el tráfico adecuadamente utilizando PBR.

Refinamientos

  • Con la solución de par de firewall, es bueno si puede sincronizar los estados de TCP a través de los firewalls, de modo que cuando un firewall falla, todo falla sin problemas al otro. Puedes lograr esto con pfsync.
    • Tenga en cuenta que pfsyncnormalmente duplicará la tasa de paquetes en sus firewalls.
    • HTTP es un protocolo sin estado, por lo que no es el fin del mundo si restablece todas las conexiones durante una conmutación por error del firewall porque no lo utiliza pfsync.
  • Si supera un solo firewall, puede usar ECMP en su enrutador para enrutar su tráfico a más de un par de firewall.
  • Si usa más de un par de cortafuegos, es mejor que los active o active. Puede lograr esto haciendo que los cortafuegos mantengan una sesión BGP con los enrutadores, al igual que las interfaces necesitan mantener uno en el segundo diseño sin cortafuegos.

relaydConfiguración de muestra

Vea también COMO en https://calomel.org/relayd.html

vip = "1.2.3.4" # Su dirección IP pública
               # (puede tener más de uno, pero no es necesario)
fe1 = "10.1.2.101"
fe2 = "10.1.2.102"
fe3 = "10.1.2.103"
fe4 = "10.1.2.104" # Puede tener cualquier cantidad de interfaces.
int_if = "em0"
tabla <fe> {$ fe1 reintento 2, $ fe2 reintento 2, $ fe3 reintento 2, $ fe4 reintento 2}
tabla <caída> {127.0.0.1}

redirigir tráfico web {
        escuchar en $ vip puerto 80
        tiempo de espera de sesión 60
        ruta a <fe> verifique la interfaz http "/healthcheck.html" digest "(sha1sum of healthcheck.html)" $ int_if
}

2

Personalmente, voy a equilibradores de carga de hardware más simples y menos configurables en ese momento, cosas como ACE / ASA de Cisco, Foundry ServerIrons, tal vez incluso Zeus ZXTM (un SW LB diseñado para cargas muy pesadas).


En otras palabras escalar hacia arriba ? Tal LB todavía se maximizará en cierto número de conexiones (etc.). ¿Entonces que? Esa es realmente mi pregunta. ¡Gracias!
z8000

1
Los sitios realmente grandes solo usan muchos LB de servicio pesado que se ejecutan bajo alguna forma de DNS round-robin: es lo suficientemente bueno por el momento para la mayoría y pueden manejar cientos de millones de conexiones. Dicho esto, está la cuestión de por qué tantas conexiones deben permanecer abiertas, por supuesto ...
Chopper3

¿Es eso RRDNS interno que quieres decir? Genial, no pensé en eso. Re: abrir conexiones ... Estoy explorando opciones para una aplicación que requiere enviar actualizaciones a clientes conectados a lo largo del tiempo a medida que ocurren eventos en algún lugar del back-end. Estoy dividido entre un servidor TCP personalizado o muchas conexiones HTTP abiertas detrás de un SLB. Gracias por tus comentarios.
z8000

Creo que debería ser RRDNS externo. Por ejemplo, Twitter.com usaría RRDNS para resolver y distribuir solicitudes a uno de los muchos LB grandes que luego distribuirían la carga a los servidores.
Robert

Sí, Robert, tienes razón, por ejemplo, utilizamos cajas GSS de Cisco para hacer RR sitio por sitio.
Chopper3

1

¿Quizás en lugar de mantener constantemente tantas conexiones abiertas para enviar respuestas, codifique su aplicación de tal manera que los clientes consulten periódicamente sus servidores con la frecuencia necesaria?

¿Lo que está haciendo realmente requiere una respuesta de este milisegundo o un cliente puede esperar 15/20 segundos hasta el próximo período de votación?


0

Un enfoque típico sería crear un clúster lo suficientemente grande como para manejar la carga requerida y usar un SLB que pueda hacer un equilibrio de carga determinista (para el caso de conexiones persistentes).

Algo así como CARP utiliza un hash de la IP solicitante para determinar qué servidor web de fondo manejaría la solicitud, esto debería ser determinista pero no muy útil si hay un firewall o NAT frente a su equilibrador de carga.
También puede encontrar algo como IPVS útil si está ejecutando en Linux.


Lo que afirmas sobre la carpa está tan lejos de cómo funciona, ¡no sabría por dónde empezar! + -0 por mencionar IPVS.
3molo

@ 3molo ... ¿eh? consulte net.inet.carp.arpbalance en linux.com/archive/feed/35482 ". El código fuente hash CARP utiliza la IP de origen de una solicitud. El hash se utiliza para seleccionar un host virtual del grupo disponible para manejar la solicitud ".
Paul
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.