En el contexto de los servidores web, el balanceo de carga es una técnica que permite distribuir el tráfico a una granja de servidores. Los clientes que se conecten a nuestro sistema web sólo accederán a través de un único punto de entrada, que será el balanceador de carga, el cual, de forma transparente dirigirá el tráfico a uno de los nodos HTTP disponibles.
Un balanceador de carga, además ofrece numerosas ventajas, como por ejemplo:
Cuando queremos montar una granja de servidores web redundante al que se accede a través de un "frontal" balanceador de carga, tenemos varias alternativas, tanto hardware (balanceadores dedicados) como software (por ejemplo con HAProxy). En cualquiera de los casos, debemos configurar en el balanceador un mecanismo de sondeo que le permita determinar si los nodos de la granja de servidores HTTP están activos o no.
Estos mecanismos de sondeo ("probe") pueden variar dependiendo de las características de nuestro sistema, y suelen abarcar sondeos basados en comprobaciones TCP, ICMP o sondeos a nivel de aplicación, como por ejemplo sondeos HTTP, en el cual el balanceador lanza una petición HTTP a los servidores de la granja y espera recibir una respuesta HTTP/1.1 200 OK para considerar que el nodo está activo y puede aceptar peticiones o cualquier otra (HTTP/1.1 4XX ó 5XX) para indicar que el nodo está offline.
Este tipo de sondeos tienen el inconveniente de que no reportan al balanceador el estado del nodo, de manera que puede que se encuentre muy sobrecargado porque las últimas conexiones que ha recibido han provocado que se ejecuten scripts que requieren muchos recursos (CPU, RAM, I/O, ...) y, aunque no se haya superado el límite de procesos que puede manejar el servidor web, el sistema puede estar ya al límite. La designación de carga asimétrica mediante un sistema de pesos en el balanceador puede ayudar a mitigar el problema pero no lo resuelve de forma efectiva, ya que en situaciones de alta carga general, recibir un 20% de muchísimo sigue siendo muchísimo y se puede dar la situación de que algunos nodos estén sobrecargados mientras otros están desocupados y que el balanceador les siga asignando trabajo ya que el sondeo anterior solo comprueba que el nodo puede aceptar conexiones. Esta situación puede hacer incluso que podamos llegar a perder el control de los servidores web sobrecargados si empiezan a hacer swapping, ya que llegados a este punto el sistema suele quedar "muerto".
En este caso, lo ideal sería que el sondeo se basara en el estado real de carga de los nodos de la granja de servidores, independientemente de los pesos asignados a cada uno de ellos. De esta manera, si el balanceador detecta que un nodo está muy sobrecargado, lo puede sacar del reparto de tareas hasta que su nivel de carga descienda de nuevo a límites aceptables. El sistema seguirá siendo el mismo de antes, basado en la respuesta HTTP. Si tenemos una respuesta 200 OK significará que el nodo puede seguir aceptando carga. Si por el contrario el nodo informa con una respuesta 503 Service Unavailable, significará que está sobrecargado y el balanceador lo dejará offline, aunque seguirá siendo sondeado en espera de que vuelva a devolver un 200 OK.
Este script "loadtest.sh" hace justamente esa tarea, basándose en la carga media del sistema para el último minuto:
En este script (ver líneas en negrita) el límite de carga antes de devolver un 503 se pone a 6 veces el nº real de CPUs (sin contar Hypertrheading). Si esto es demasiado para vuestro sistema, bajad el multiplicador al límite que consideréis adecuado. En los servidores web que administro, el sistema sigue funcionando correctamente cuando se alcanza esta carga, aunque puede que no sea vuestro caso.
Para instalar el script, en un servidor web Apache bajo Debian GNU/Linux, lo podemos hacer de la siguiente manera:
1) Crear el fichero /etc/apache2/sites-available/loadtest con el siguiente contenido, adaptando la ruta al sitio donde hayamos instalado nuestro script loadtest.sh.
2) Dar permisos de ejecución al script (adaptando la ruta) con el comando:
3) Habilitar el site en el apache con el comando:
4) Recargar la configuración del servidor web:
Ya podemos probar nuestro script cargando la URL /loadtest desde cualquier navegador. Obtendremos una salida similar a esta:
Si examinamos los encabezados devueltos con CURL, podremos ver la respuesta 200 OK / 503 Service Unavailable:
5) Por último, tenemos que configurar el sondeo de nuestro balanceador para que haga uso de la URL con nuestro script, indicando que la respuesta 200 es la esperada para indicar que el nodo está activo y acepta conexiones y que cualquier otra cosa que se reciba indica que hay que dejar al nodo temporalmente fuera de la granja.
Espero que os sea útil. Por favor, dejad vuestros comentarios y sugerencias.
Mario J. Barchéin Molina.
Un balanceador de carga, además ofrece numerosas ventajas, como por ejemplo:
- Puede actuar como firewall.
- Puede asignar cargas de trabajo asimétricas, de manera que algunos nodos reciban más o menos peticiones en función de sus capacidades.
- Tolerancia a fallos de los nodos servidores HTTP.
- Monitorización del estado de "salud" de los nodos servidores.
Cuando queremos montar una granja de servidores web redundante al que se accede a través de un "frontal" balanceador de carga, tenemos varias alternativas, tanto hardware (balanceadores dedicados) como software (por ejemplo con HAProxy). En cualquiera de los casos, debemos configurar en el balanceador un mecanismo de sondeo que le permita determinar si los nodos de la granja de servidores HTTP están activos o no.
Estos mecanismos de sondeo ("probe") pueden variar dependiendo de las características de nuestro sistema, y suelen abarcar sondeos basados en comprobaciones TCP, ICMP o sondeos a nivel de aplicación, como por ejemplo sondeos HTTP, en el cual el balanceador lanza una petición HTTP a los servidores de la granja y espera recibir una respuesta HTTP/1.1 200 OK para considerar que el nodo está activo y puede aceptar peticiones o cualquier otra (HTTP/1.1 4XX ó 5XX) para indicar que el nodo está offline.
Este tipo de sondeos tienen el inconveniente de que no reportan al balanceador el estado del nodo, de manera que puede que se encuentre muy sobrecargado porque las últimas conexiones que ha recibido han provocado que se ejecuten scripts que requieren muchos recursos (CPU, RAM, I/O, ...) y, aunque no se haya superado el límite de procesos que puede manejar el servidor web, el sistema puede estar ya al límite. La designación de carga asimétrica mediante un sistema de pesos en el balanceador puede ayudar a mitigar el problema pero no lo resuelve de forma efectiva, ya que en situaciones de alta carga general, recibir un 20% de muchísimo sigue siendo muchísimo y se puede dar la situación de que algunos nodos estén sobrecargados mientras otros están desocupados y que el balanceador les siga asignando trabajo ya que el sondeo anterior solo comprueba que el nodo puede aceptar conexiones. Esta situación puede hacer incluso que podamos llegar a perder el control de los servidores web sobrecargados si empiezan a hacer swapping, ya que llegados a este punto el sistema suele quedar "muerto".
En este caso, lo ideal sería que el sondeo se basara en el estado real de carga de los nodos de la granja de servidores, independientemente de los pesos asignados a cada uno de ellos. De esta manera, si el balanceador detecta que un nodo está muy sobrecargado, lo puede sacar del reparto de tareas hasta que su nivel de carga descienda de nuevo a límites aceptables. El sistema seguirá siendo el mismo de antes, basado en la respuesta HTTP. Si tenemos una respuesta 200 OK significará que el nodo puede seguir aceptando carga. Si por el contrario el nodo informa con una respuesta 503 Service Unavailable, significará que está sobrecargado y el balanceador lo dejará offline, aunque seguirá siendo sondeado en espera de que vuelva a devolver un 200 OK.
Este script "loadtest.sh" hace justamente esa tarea, basándose en la carga media del sistema para el último minuto:
#!/bin/bash ## carga del sistema loadavg=`cat /proc/loadavg` ## nº de procesadores nprocessors=`cat /proc/cpuinfo | egrep processor | wc -l` ht=`cat /proc/cpuinfo | egrep 'flags.+\bht\b' | wc -l` ## En un sistema con HyperThreading el nº de ## procesadores es la mitad if (( $ht > 0 )) then nprocessors=$((nprocessors / 2)) fi ## carga máxima permitida (adaptar) maxload=$((nprocessors * 6)) ## carga media del último minuto load1m=${loadavg%% *} load1mint=${loadavg%%.*} ## ¿se supera la carga? if (( $load1mint < $maxload )) then echo "Status: 200 OK" echo "Content-Type: text/plain" echo echo "OK" else echo "Status: 503 Service Unavailable" echo "Content-Type: text/plain" echo echo "REJECT" fi ## información acerca del nodo cat /etc/hostname echo load: $load1m echo processors: $nprocessors echo max allowed load: $maxload
En este script (ver líneas en negrita) el límite de carga antes de devolver un 503 se pone a 6 veces el nº real de CPUs (sin contar Hypertrheading). Si esto es demasiado para vuestro sistema, bajad el multiplicador al límite que consideréis adecuado. En los servidores web que administro, el sistema sigue funcionando correctamente cuando se alcanza esta carga, aunque puede que no sea vuestro caso.
Para instalar el script, en un servidor web Apache bajo Debian GNU/Linux, lo podemos hacer de la siguiente manera:
1) Crear el fichero /etc/apache2/sites-available/loadtest con el siguiente contenido, adaptando la ruta al sitio donde hayamos instalado nuestro script loadtest.sh.
## Medidor de carga del sistema (usado por el balanceador) ScriptAlias /loadtest /var/www-data/loadtest.sh <location /loadtest> Order deny,allow Allow from all </location>
2) Dar permisos de ejecución al script (adaptando la ruta) con el comando:
# chmod 755 /var/www-data/loadtest.sh
3) Habilitar el site en el apache con el comando:
# a2ensite loadtest
4) Recargar la configuración del servidor web:
# /etc/init.d/apache2 reload
Ya podemos probar nuestro script cargando la URL /loadtest desde cualquier navegador. Obtendremos una salida similar a esta:
OK granja01 load: 0.13 processors: 4 max allowed load: 24.00
Si examinamos los encabezados devueltos con CURL, podremos ver la respuesta 200 OK / 503 Service Unavailable:
$ curl -I http://localhost/loadtest HTTP/1.1 200 OK Date: Sun, 12 Feb 2012 23:29:30 GMT Server: Apache/2.2.16 (Debian) Vary: Accept-Encoding Content-Type: text/plain
5) Por último, tenemos que configurar el sondeo de nuestro balanceador para que haga uso de la URL con nuestro script, indicando que la respuesta 200 es la esperada para indicar que el nodo está activo y acepta conexiones y que cualquier otra cosa que se reciba indica que hay que dejar al nodo temporalmente fuera de la granja.
Espero que os sea útil. Por favor, dejad vuestros comentarios y sugerencias.
Mario J. Barchéin Molina.
muy buen post.
ResponderEliminarMuchas gracias amigo !!
ResponderEliminarsaludos amigo ...gracias!!!
ResponderEliminarmuy buen post
ResponderEliminarSaludos, existe algo asi para servidores virtuales?
ResponderEliminargracias
Buen articulo
ResponderEliminarExcelente post
ResponderEliminarhola, muy interesante la informacion y además muy entendible, una pregunta ¿Tienes más información al respecto? esto, porque quiero hacer eso con una aplicación que tengo, por el momento esta distribuida en tres servidores pero necesito un unico punto de entrada y de ahi mandar a cualquiera de los servidores y poder hacer dashboard o saber la carga de los servidores etc,gracias.
ResponderEliminarPuedes tener un único punto de entrada en otro nodo con nginx, por ejemplo y redirigir al los servidores upstream. Mira http://nginx.org/en/docs/http/load_balancing.html
Eliminar