Balanceo de carga con HAproxy

CDA 2022/23


Índice General

1 Descripción

Uso de HAproxy como balanceador de carga a nivel de aplicación para servidores web.

Recursos complementarios

2 Entorno de prácticas

2.1 Software de virtualización VIRTUALBOX

En estas prácticas se empleará el software de virtualización VIRTUALBOX para simular los equipos GNU/Linux sobre los que se realizarán las pruebas.

2.2 Imágenes a utilizar

  1. Scripts de instalación

    Notas:

  2. Imágenes descargadas

  3. Usuarios configurados e inicio en el sistema

2.3 Máquinas virtuales y redes creadas

Image haproxy

3 HAProxy

HAProxy es un proyecto open source que ofrece un balanceador de carga implementado como un proxy inverso que reparte conexiones a nivel HTTP o TCP entre un conjunto de servidores reales.

3.1 Funcionamiento y funcionalidades

HAProxy es un balanceador de carga que funciona como un proxy inverso (reverse proxy) repartiendo las conexiones recibidas de los clientes entre un conjunto de ”servidores reales”.

Funcionalidades

Detalles en http://docs.haproxy.org/2.2/intro.html3

3.2 Configuración

Configuración por defecto en /etc/haproxy/haproxy.cfg

Fichero de configuración organizado en secciones

global
Parámetros globales
defaults
Valores por defecto de parámetros usados en el resto de secciones (pueden sobreescribirse posteriormente)
frontend
Definición y parámetros de un frontend (pueden definirse varios)

backend
Definición y parámetros de un backend (pueden definirse varios)
listen
Sección opcional que combina la definición de un frontend y un backend para describir un proxy inverso completo.

Detalles en http://docs.haproxy.org/2.2/configuration.html#2

4 EJERCICIO ENTREGABLE: Balanceo de carga en servidores Apache con HAproxy

4.1 Pasos previos

  1. Arrancar el entorno gráfico en cliente [193.147.87.33]
    cliente:~# startx
    

  2. Ajustar la configuración de las dos máquinas del cluster de balanceo (apache1 y apache2)
    1. Deshabilitar la opción KeepAlive en el fichero de configuración /etc/apache2/apache2.conf para realizar la evaluación del rendimiento sin la opción de reutilización de conexiones.
      	    apache1:~# nano /etc/apache2/apache2.conf  
      	       ...
      	       KeepAlive Off
      	       ...
      

      	    apache2:~# nano /etc/apache2/apache2.conf  
      	       ...
      	       KeepAlive Off
      	       ...
      

      Nota:

      • este ajuste no es estrictemente necesario (y sería desaconsejable en un entorno de producción real), pero facilita las pruebas manueles dado que permite detectar inmediatamente el ”cambio” de destino resultado del balanceo de carga
      • manteniendo la opción por defecto, en las pruebas manuales desde el navegador sería necesario esperar 5 segundos (el time out de keep alive) antes de recargar la página y ver el efecto del reparto de carga

    2. Editar los archivos del sitio web para incluir una indicación del servidor real que está sirviendo una petición, de modo que sea posible ”diferenciarlos” en las pruebas manuales con el navegador
      • en apache1
        	    apache1:~# nano /var/www/html/index.html
        	       ...
        	       <h1> Servidor por APACHE_UNO </h1>
        	       ...
        

        	    apache1:~# nano /var/www/html/sesion.php	
        	       ...
        	       <h1> Servido por APACHE_UNO </h1>
        	       ...
        

      • en apache2
        	    apache2:~# nano /var/www/html/index.html
        	       ...
        	       <h1> Servido por APACHE_DOS </h1>
        	       ...
        

        	    apache2:~# nano /var/www/html/sesion.php	
        	       ...
        	       <h1> Servido por APACHE_DOS </h1>
        	       ...
        

      Notas:

      • este ajuste es simplemente una herramienta de depuración para verificar que el balanceador funciona correctamente
      • en una ”granja” de servidores real este comportamiento no tendría sentido, dado que, obviamente, todos los nodos servirían el mismo contenido/aplicaciones (normalmente almacenado de forma compartido en una SAN o soluciones similares)

    3. [Importante] Corregir en ambas máquinas (apache1, apache2) el script PHP sleep.php usado en las pruebas

       apache1~:# nano /var/www/html/sleep.php
        
       apache2~:# nano /var/www/html/sleep.php
      

      Nuevo contenido (reemplaza el existente)

      <html>
      <title> Página dinámica con retardo </title>
      <body>
        <h1> Prueba dinámica con retardo </h1>
        <p> hora de inicio: <?php echo date('h:i:s'); ?> </p>
       
        <?php  
        for ($i=0; $i < 100000; $i++) {       // <- poner 100000 iteraciones
           $str1 = sha1(rand()*rand());       // <- tres llamadas a sha1()
           $str2 = sha1(rand()*rand());
           $str3 = sha1(rand()*rand());
        }
        ?>
       
        <p> hora de fin: <?php echo date('h:i:s'); ?> </p>
      </body>
      </html>
      

      Comprobación

       apache1~:# php /var/www/sleep.php
       
       apache2~:# php /var/www/sleep.php
      

4.2 Tarea 1: evaluar rendimiento de un servidor Apache sin balanceo

Se realizarán varias pruebas de carga sobre el servidor Apache ubicado en la máquina apache1 para determinar el rendimiento que puede llegar a ofrecer una instancia única del servidor Apache.

Pasos a realizar

  1. Parar el servicio haproxy en balanceador [193.147.87.47] (por defecto está arrancado, aunque no configurado)
    	    balanceador:~# systemctl stop haproxy
    
  2. Parar el servidor apache2 en balanceador [193.147.87.47], en caso de estar iniciado
    	    balanceador:~# systemctl stop apache2
    

    Nota: En ocasiones no tiene efecto la parada del servicio apache2, puede comprobarse si el proceso sigue en ejecución con pidof apache2 y ”matar” los posibles procesos supervivientes si fuera necesario.

    	    balanceador:~# pidof apache2 
    	    wwww xxxx yyyy zzzz
    	    balanceador:~# kill -9 wwww xxxx yyyy zzzz
    

  3. Habilitar en balanceador [193.147.87.47] la redirección de puertos para que sea accesible el servidor Apache de la máquina apache1 [10.10.10.11] empleando el siguiente comando iptables
    	    balanceador:~# echo 1 > /proc/sys/net/ipv4/ip_forward
    	    
    	    balanceador:~# iptables -P FORWARD ACCEPT
    	    
    	    balanceador:~# iptables -t nat -A PREROUTING \
    	                            --in-interface enp0s3 --protocol tcp --dport 80 \
    	                            -j DNAT --to-destination 10.10.10.11
    

    Notas:

  4. Arrancar (o reiniciar) en apache1 [10.10.10.11] el servidor web Apache
    	    apache1:~# systemctl restart apache2      #(ó     systemctl start apache2)
    

    Comprobación:

  5. Lanzar las pruebas de carga iniciales sobre balanceador [193.147.87.47] usando el herramienta Apache Benchmark

    En cada ejecución del comando ab se muestran las estadísticas obtenidas. Para el tipo de prueba informal que se realiza en este ejemplo, basta prestar atención a los parámetros Requests per second (num. peticiones por segundo) ó Time per request (tiempo en milisegundos para procesar cada petición).

4.3 Tarea 2: configurar y evaluar balanceo de carga con dos servidores Apache

  1. Deshabilitar la redirección del puerto 80 de la máquina balanceador [193.147.87.47] con el siguiente comando iptables (HAproxy se encargará de retransmitir ese tráfico sin necesidad de redireccionar los puertos)
    balanceador:~# iptables -t nat -F
    balanceador:~# iptables -t nat -Z
    

  2. Parar el servidor apache2 en balanceador [193.147.87.47], en caso de estar iniciado
    balanceador:~# systemctl stop apache2
    

  3. Arrancar/reiniciar los servidores Apache de apache1 [10.10.10.11] y apache2 [10.10.10.22], en caso de no estar iniciados
    apache1:~# systemctl restart apache2      #(ó     systemctl start apache2)
    		  
    apache2:~# systemctl restart apache2      #(ó     systemctl start apache2)
    

  4. Instalar HAproxy en balanceador [193.147.87.47] [ya está hecho]

    balanceador:~# apt-get update
    balanceador:~# apt-get install haproxy
    

  5. Configurar HAproxy en balanceador [193.147.87.47] (de momento sin soporte de sesiones persistentes)
    balanceador:~# cd /etc/haproxy
    balanceador:/etc/haproxy/# mv haproxy.cfg haproxy.cfg.original
    balanceador:/etc/haproxy/# nano haproxy.cfg
    

    Contenido a incluir:

    global
            daemon
            maxconn 256
            user    haproxy
            group   haproxy
    
    defaults
            mode    http
            log     global
            timeout connect 5000ms
            timeout client  50000ms
            timeout server  50000ms
    
    frontend web_cda 
            bind 193.147.87.47:80
            mode http
            stats enable
            stats auth  cda:cda
            default_backend servidores_cda
            
    backend servidores_cda
            balance roundrobin
            server uno 10.10.10.11:80 maxconn 128
            server dos 10.10.10.22:80 maxconn 128
    

    Define (en la sección frontend) un ”proxy inverso” de nombre web_cda que:

    1. trabajará en modo http (la otra alternativa es el modo tcp, pero no analiza las peticiones/respuestas HTTP, sólo retransmite paquetes TCP a nivel de capa de transporte)
    2. atendiendo peticiones en el puerto 80 de la dirección 193.147.87.47
    3. las peticiones se repartirán en el cluster servidores_cda
    4. adicionalmente, habilita la consola Web de estadísticas, accesible con las credenciales cda:cda
    Define (en la sección backend) la lista de servidores reales servidores_cda
    1. con balanceo round-robin
    2. formada por dos servidores reales (de nombres uno y dos) en el puerto 80 de las direcciones 10.10.10.11 y 10.10.10.22

    Más detalles en Opciones de configuración HAPproxy 2.2

  6. Iniciar HAproxy en balanceador [193.147.87.47]

    Antes de hacerlo es necesario habilitar en /etc/default/haproxy el arranque de HAproxy desde los scripts de inicio de Debian, estableciendo la variable ENABLED=1

        balanceador:/etc/haproxy/# nano  /etc/default/haproxy
        
        ...
        ENABLED=1
    

    Inicio empleando el script de arranque de HAproxy (preferente)

    balanceador:/etc/haproxy/# systemctl stop  haproxy    # ya estaba arrancado
    balanceador:/etc/haproxy/# systemctl start haproxy
    

  7. Comprobar funcionamiento del balancenador: desde la máquina cliente [193.147.87.33] abrir la URL http://193.147.87.47 en el navegador web en modod texto lynx y recargar varias veces con [Control]+R para comprobar como cambia el servidor real que responde las peticiones.
    cliente:~#  lynx 193.147.87.47
    
    Nota: El navegador gráfico Falkon hace caché de las páginas cargadas y no permite comprobar el balanceo de carga directamente recargando la página.

    Nota: Si no se ha deshabilitado la opción KeepAlive de Apache, es necesario esperar 5 segundos entre las recargas para que se agote el tiempo de espera para cerrar completamente la conexión HTTP y que pase a ser atendida por otro servidor.

  8. Desde la máquina cliente [193.147.87.33] repetir las pruebas de carga con ab

    Pruebas a realizar:

    cliente:~# ab -n 2000 -c 10 http://193.147.87.47/index.html
    cliente:~# ab -n 2000 -c 50 http://193.147.87.47/index.html
    
    cliente:~# ab -n 250 -c 10 http://193.147.87.47/sleep.php
    cliente:~# ab -n 250 -c 30 http://193.147.87.47/sleep.php
    

    Los resultados deberían de ser mejores que con la prueba anterior con un servidor Apache único (al menos en el caso del script sleep.php)

  9. Desde la máquina cliente [193.147.87.33] abrir en el navegador web Falkon la URL http://193.147.87.47/haproxy?stats para inspeccionar las estadísticas del balanceador HAProxy (pedirá un usuario y un password, ambos cda)

  10. Desde uno de los servidores (apache1 ó apache2), verificar los logs del servidor Apache
    apache1:~# tail /var/log/apache2/error.log        apache2:~# tail /var/log/apache2/error.log
    apache1:~# tail /var/log/apache2/access.log       apache2:~# tail /var/log/apache2/access.log
    

  11. Cuestión 1. En todos los casos debería figurar como única dirección IP cliente la IP interna de la máquina balanceador [10.10.10.1]. ¿Por qué?

4.4 Tarea 3: configurar la persistencia de conexiones Web (sticky sessions)

Comprobar el contenido del fichero PHP /var/www/html/sesion.php disponible en las máquinas apache1 [10.10.10.11] y apache2 [10.10.10.22].

Se puede verificar el funcionamiento ”defectuoso” del balanceo de carga por defecto (round robin sin seguimiento de cookies), accediendo desde la máquina cliente a la URL http://193.147.87.47/sesion.php con el navegador en modo texto lynx y recargando la página varias veces con [Control]+R.

	cliente:~# lynx -accept-all-cookies  http://193.147.87.47/sesion.php

Para solucionarlo es necesario configurar HAProxy para que haga el seguimiento de las cookies de sesión. De tal modo que no se aplique el balanceo de carga, asignado el mismo servidor real que estableció una cookie determinada en un parámetro SET_COOKIE de una HTTP response.

  1. Detener HAproxy en la máquina balanceador [193.147.87.47]
    balanceador:/etc/haproxy/# systemctl stop haproxy
    
  2. Añadir las opciones de persistencia de conexiones HTTP (sticky cookies) al fichero de configuración
    balanceador:~# nano /etc/haproxy/haproxy.cfg
    

    Contenido a incluir: (añadidos marcados con <- aqui)

    global
            daemon
            maxconn 256
            user    haproxy
            group   haproxy
    
    defaults
            mode    http
            log     global
            timeout connect 10000ms
            timeout client  50000ms
            timeout server  50000ms
    
    frontend web_cda 
            bind 193.147.87.47:80
            mode http
            stats enable
            stats auth  cda:cda
            default_backend servidores_cda
    
    backend servidores_cda
            balance roundrobin
            cookie PHPSESSID prefix                             # <- aqui
            server uno 10.10.10.11:80 cookie ZIPI maxconn 128   # <- aqui
            server dos 10.10.10.22:80 cookie ZAPE maxconn 128   # <- aqui
    

    El parámetro cookie especifica el nombre de la cookie que se usa como identificador único de la sesión del cliente (en el caso de aplicaciones web PHP se suele utilizar por defecto el nombre PHPSESSID)

  3. Iniciar HAproxy en la máquina balanceador [193.147.87.47]
    balanceador:/etc/haproxy/# systemctl start haproxy
    

  4. En la máquina cliente [193.147.87.33], arrancar el sniffer de red whireshark y ponerlo en escucha sobre el interfaz enp0s3 (puede fijarse como filtro la cadena http para que solo muestre las peticiones y respuestas HTTP)

    cliente:~# wireshark &
    

  5. En la máquina cliente [193.147.87.33] (recarga con [control]+R)
  6. Detener la captura de tráfico en wireshark y comprobar las peticiones/respuestas HTTP capturadas

    Verificar la estructura y valores de las cookies PHPSESSID intercambiadas

5 Documentación a entregar

Entrega: MOOVI (práctica individual)

Fecha límite: hasta el domingo 27/11/2022