Introducción
HAProxy es un software de código abierto que puede balancear la carga de servidores HTTP y TCP. En el artículo anterior sobre HAProxy, configuramos el balanceo de carga en la capa 4 y en este, haremos lo mismo para MySQL. Todos los servidores MySQL deben configurarse para realizar la replicación Master-Master, ya que el equilibrio de carga implica la lectura y la escritura en todos los backends.
Los siguientes tres droplets se utilizarán en este artículo:
Droplet 1 – Balanceador de carga
Nombre de host: haproxy
Sistema operativo: Ubuntu
IP Privada: 10.0.0.100
Droplet 2 – Nodo 1
Nombre de host: mysql-1
Sistema operativo: Debian 7
IP Privada: 10.0.0.1
Droplet 3 – Nodo 2
Nombre de host: mysql-2
Sistema operativo: Debian 7
IP Privada: 10.0.0.2
Antes de continuar, asegúrate de que todos los servidores MySQL estén funcionando, ejecutando y replicando correctamente las escrituras de la base de datos.
Preparar los servidores MySQL
Necesitamos preparar los servidores MySQL creando dos usuarios adicionales para HAProxy. El primer usuario será utilizado por HAProxy para verificar el estado de un servidor.
1 2 |
root@mysql-1# mysql -u root -p -e "INSERT INTO mysql.user (Host,User) values ('10.0.0.100','haproxy_check'); FLUSH PRIVILEGES;" |
Se necesita un usuario de MySQL con privilegios de root al acceder al clúster de MySQL desde HAProxy. El usuario root predeterminado en todos los servidores puede iniciar sesión solo localmente. Si bien esto puede solucionarse otorgando privilegios adicionales al usuario root, es mejor tener un usuario separado con privilegios de root.
1 2 |
root@mysql-1# mysql -u root -p -e "GRANT ALL PRIVILEGES ON *.* TO 'haproxy_root'@'10.0.0.100' IDENTIFIED BY 'password' WITH GRANT OPTION; FLUSH PRIVILEGES" |
Debes reemplaza haproxy_root y password con tus propios valores. Es suficiente ejecutar estas consultas en un master de MySQL, ya que los cambios se replicarán en otros.
Instalar el cliente MySQL
El cliente MySQL debe instalarse en el droplet HAProxy para probar la conectividad.
1 |
root@haproxy# apt-get install mysql-client |
Ahora intenta ejecutar una consulta en uno de los master como el usuario haproxy_root.
1 |
root@haproxy# mysql -h 10.0.0.1 -u haproxy_root -p -e "SHOW DATABASES" |
Esto debería mostrar una lista de bases de datos MySQL.
Instalación de HAProxy
En el servidor HAProxy instala el siguiente paquete:
1 |
root@haproxy# apt-get install haproxy |
Debes permitir que HAProxy se inicie con el script de inicio.
1 |
root@haproxy# sed -i "s/ENABLED=0/ENABLED=1/" /etc/default/haproxy |
Para comprobar si este cambio se realiza correctamente, ejecuta el script de inicio de HAProxy sin ningún parámetro.
1 2 |
root@haproxy:~# service haproxy Usage: /etc/init.d/haproxy {start|stop|reload|restart|status} |
Configurando HAProxy
Debes renombrar el archivo de configuración original
1 |
mv /etc/haproxy/haproxy.cfg{,.original} |
Crea y edita uno nuevo.
1 |
nano /etc/haproxy/haproxy.cfg |
El primer bloque es el bloque de configuración global y por defecto.
1 2 3 4 5 6 7 8 9 10 11 |
global log 127.0.0.1 local0 notice user haproxy group haproxy defaults log global retries 2 timeout connect 3000 timeout server 5000 timeout client 5000 |
En este artículo se cubre más información sobre cada una de estas opciones . Como le hemos dicho a HAProxy que envíe mensajes de registro a 127.0.0.1, tenemos que configurar rsyslog para que escuche. Esto también se ha cubierto en el mismo artículo en Configurar registro para HAProxy.
Pasando a la parte de configuración principal.
1 2 3 4 5 6 7 |
listen mysql-cluster bind 127.0.0.1:3306 mode tcp option mysql-check user haproxy_check balance roundrobin server mysql-1 10.0.0.1:3306 check server mysql-2 10.0.0.2:3306 check |
A diferencia del balanceo de carga HTTP, HAProxy no tiene un “modo” específico para MySQL, por lo que usamos tcp. Hemos configurado HAProxy para escuchar solo en la dirección de bucle de retorno (suponiendo que la aplicación está en el mismo servidor), sin embargo, si tu aplicación reside en un droplet diferente, hazlo escuchar en 0.0.0.0 o en la dirección IP privada.
Necesitamos un bloque de configuración más para ver las estadísticas de balanceo de carga. Esto es completamente opcional y puede omitirse si no quieres estadísticas.
1 2 3 4 5 6 7 |
listen 0.0.0.0:8080 mode http stats enable stats uri / stats realm Strictly\ Private stats auth A_Username:YourPassword stats auth Another_User:passwd |
Reemplaza los usernames y password en “stats auth”. Esto hará que HAProxy escuche en el puerto 8080 las solicitudes HTTP y las estadísticas estarán protegidas con la autenticación básica HTTP. Para que puedas acceder a las estadísticas hazlo en:
1 |
http://<IP publica balanceador de carga>:8080/ |
Una vez que hayas terminado de configurar, inicia el servicio HAProxy.
1 |
service haproxy start |
Utiliza el cliente mysql para consultar HAProxy.
1 |
root@haproxy# mysql -h 127.0.0.1 -u haproxy_root -p -e "SHOW DATABASES" |
La opción “-h” tiene que estar presente con la dirección IP de bucle de retorno. Omitirlo o usar localhost hará que el cliente MySQL se conecte al archivo mysql.sock, el cual fallará.
Prueba de balanceo de carga y conmutación por error
Para verificar si el balanceo de carga está funcionando, consulta la variable server_id dos veces o más.
1 2 3 4 5 6 7 8 9 10 11 12 |
root@haproxy# mysql -h 127.0.0.1 -u haproxy_root -p -e "show variables like 'server_id'" +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id | 1 | +---------------+-------+ root@haproxy# mysql -h 127.0.0.1 -u haproxy_root -p -e "show variables like 'server_id'" +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id | 2 | +---------------+-------+ |
Esto demuestra el balanceo de carga de roundrobin con pesos iguales, ahora cambiaremos el peso de mysql-2 y veremos los resultados.
nano /etc/haproxy/haproxy.cfg
1 |
server mysql-2 10.0.0.2:3306 check weight 2 |
Debes recargar para aplicar este cambio.
1 |
service haproxy reload |
Consulta para el server_id varias veces.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
root@haproxy:~# for i in `seq 1 6` do mysql -h 127.0.0.1 -u haproxy_root -ppassword -e "show variables like 'server_id'" done +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id | 1 | +---------------+-------+ +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id | 2 | +---------------+-------+ +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id | 2 | +---------------+-------+ +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id | 1 | +---------------+-------+ +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id | 2 | +---------------+-------+ +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id | 2 | +---------------+-------+ |
Ahora el balanceo de carga funciona en una proporción de 1:2 con un tercio de las solicitudes que van a mysql-1 y dos tercios que van a mysql-2.
Si falla un servidor MySQL ya sea deteniendo el servicio
1 |
root@mysql-1# service mysql stop |
o deteniendo la interfaz.
1 |
root@mysql-1# ifconfig eth1 down |
Prueba la consulta ” show variables” ahora para ver el resultado. Las siguientes entradas de registro indicarán cuándo y cómo HAProxy detectó el error.
tail /var/log/haproxy/haproxy.log
1 |
Nov 15 00:08:51 localhost haproxy[1671]: Server mysql-cluster/mysql-1 is DOWN, reason: Layer4 timeout, check duration: 2002ms. 1 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue. |
Reducir el intervalo de conmutación por error
Cuando un servidor MySQL deja de funcionar, HAProxy tarda algún tiempo en detectar este error y eliminarlo del clúster. En esta sección veremos cómo controlar esta vez. Primero veremos cómo medir este valor. Una forma es bloquear el puerto MySQL usando iptables durante un cierto tiempo, luego eliminar la regla y verificar el registro.
1 2 3 4 5 6 7 8 |
root@mysql-1:~# ifconfig eth1 down && date && sleep 20 && ifconfig eth1 up && date Fri Nov 15 00:37:09 IST 2013 Fri Nov 15 00:37:29 IST 2013 |
El puerto 3306 se bloqueó durante 20 segundos, veremos el archivo de registro ahora.
1 2 3 4 5 6 7 |
root@haproxy:~# tail /var/log/haproxy.log Nov 15 16:49:38 localhost haproxy[1275]: Server mysql-cluster/mysql-1 is DOWN, reason: Layer4 connection problem, info: "Connection refused", check duration: 0ms. 1 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue. Nov 15 16:49:56 localhost haproxy[1275]: Server mysql-cluster/mysql-1 is UP, reason: Layer7 check passed, code: 0, info: "5.5.31-0+wheezy1-log", check duration: 1ms. 2 active and 0 backup servers online. 0 sessions requeued, 0 total in queue. |
Tardó 6 segundos en detectar una falla (diferencia entre 16:49:38 y 16:49:32) y 4 segundos para detectar que se puede llegar al servidor (diferencia entre 16:49:56 y 16:49:52). Esto está determinado por los parámetros de servidor rise, fall e inter.
Parámetros
El parámetro de rise establece el número de comprobaciones que un servidor debe pasar para que se declare operativo. El valor predeterminado es 2.
El parámetro de fall establece el número de comprobaciones que debe pasar un servidor para ser declarado inactivo. El valor predeterminado es 3.
El parámetro inter establece el intervalo entre estas comprobaciones. El valor predeterminado es 2000 milisegundos.
Al reunir esta información, un servidor debe fallar 3 comprobaciones continuas que se realizan en un intervalo de 2 segundos para ser considerado muerto. Entonces, en nuestro ejemplo anterior, lo siguiente hubiera sucedido.
1 2 3 4 |
16:49:32 - Port 3306 on mysql-1 was blocked 16:49:34 - Check - Failed - Failure No. 1 16:49:36 - Check - Failed - Failure No. 2 16:49:38 - Check - Failed - Failure No. 3 (server removed and event logged) |
Y cuando se eliminó la regla de firewall.
1 2 3 |
16:49:52 - Firewall rule removed port 3306 accessible 16:49:54 - Check - Passed - Success No. 1 16:49:56 - Check - Passed - Success No. 2 (server added to cluster and event logged) |
La siguiente configuración reducirá el intervalo de prueba a 1 segundo y también reducirá el número de pruebas de caída.
nano /etc/haproxy/haproxy.cfg
1 2 |
server mysql-1 10.0.0.1:3306 check fall 2 inter 1000 server mysql-2 10.0.0.2:3306 check fall 2 inter 1000 |
En ocasiones, es posible que no desees inundar la red privada con demasiados paquetes de “prueba”, especialmente si tienes una gran cantidad de servidores MySQL. En tales casos, los parámetros fastinter y downinter serán útiles.
Parámetros
El parámetro fastinter establece el intervalo entre las comprobaciones mientras un servidor está en transición hacia UP o DOWN.
El parámetro downinter establece el intervalo de prueba cuando un servidor está DOWN.
Esa explicación puede ser confusa, así que la veremos con un ejemplo.
nano /etc/haproxy/haproxy.cfg
1 2 |
server mysql-1 10.0.0.1:3306 check fastinter 1000 server mysql-2 10.0.0.2:3306 check fastinter 1000 |
Como no hemos especificado el parámetro “inter”, el valor predeterminado es 2000ms. Con esta configuración reiniciaremos HAProxy y haremos la prueba nuevamente.
1 2 3 4 5 6 7 |
root@mysql-1:~# iptables -A INPUT -p tcp --dport 3306 -j REJECT && date && sleep 20 && iptables -D INPUT -p tcp --dport 3306 -j REJECT && date Fri Nov 15 17:18:48 IST 2013 Fri Nov 15 17:19:08 IST 2013 |
Comprueba el archivo de registro de HAProxy.
1 2 3 4 5 6 7 |
root@haproxy:~# tail /var/log/haproxy.log Nov 15 17:18:52 localhost haproxy[1353]: Server mysql-cluster/mysql-1 is DOWN, reason: Layer4 connection problem, info: "Connection refused", check duration: 0ms. 1 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue. Nov 15 17:19:11 localhost haproxy[1353]: Server mysql-cluster/mysql-1 is UP, reason: Layer7 check passed, code: 0, info: "5.5.31-0+wheezy1-log", check duration: 1ms. 2 active and 0 backup servers online. 0 sessions requeued, 0 total in queue. |
Ahora solo tomó 4 segundos (en comparación con 6 antes) para detectar una falla y 3 segundos (en comparación con 4) para detectar que el servidor estaba funcionando. Tras bambalinas esto es lo que pasó:
1 2 3 4 |
17:18:48 - Port 3306 blocked 17:18:50 - Check - Failed - Failure No. 1 17:18:51 - Check - Failed - Failure No. 2 17:18:52 - Check - Failed - Failure No. 3 (server removed and event logged) |
Y cuando el puerto fue desbloqueado.
1 2 3 |
17:19:08 - Firewall rule removed 17:19:10 - Check - Passed - Success No. 1 17:19:11 - Check - Passed - Success No. 2 (server added to cluster and event logged) |
Primero debes notar el intervalo entre el evento de bloqueo de puerto (17:18:48) y la primera verificación (17:18:50), es de 2 segundos (el intervalo “inter”). Luego observa el intervalo entre la Test 1 <-> Test 2 y Test 2<-> Test 3, es solo 1 segundo (el intervalo “fastinter”). Se pueden notar los mismos intervalos cuando el servidor se movió de DOWN a UP. Así que “fastinter” controla el intervalo entre estas comprobaciones.
Entonces, ¿qué es downinter? Cuando un servidor se ha declarado DOWN, HAProxy continúa revisándolo cada 2 segundos (o el intervalo mencionado en inter). Si crees que estás utilizando recursos de red innecesarios, configura downinter para decir que 5000 hará que HAProxy compruebe un servidor DOWN solo una vez en 5 segundos.
Importante
Las pruebas que hicimos anteriormente RECHAZARON los paquetes, lo que significa que cuando HAProxy inició una conexión al enviar un paquete SYN a mysql-1, recibió un paquete RST (en lugar de SYN + ACK). Es por esto que la entrada de registro mencionó “Conexión rechazada”. En este momento, solo funcionan los valores de fall, inter e fastinter.
En cambio, si HAProxy no recibió nada después de enviar SYN, el tiempo de conexión se agota. Para este caso, además de los parámetros mencionados anteriormente, la duración del “tiempo de espera” entra en acción. Esta situación puede suceder si:
- iptables está ajustado a DROP
- La interfaz privada no funciona
- Hay un problema con la infraestructura de redes privadas.