La instalación de un clúster MYSQL

Alta Disponibilidad en MySQL / ProxySQL

1) Arquitectura del laboratorio (lo que vas a montar)

  • 3 VMs en VMware Workstation:
    • db-master — MySQL (escrituras)
    • db-replica — MySQL (réplica; lecturas)
    • balancer — HAProxy que expondrá dos puertos:
      • puerto 3306 -> encaminado a master (escritura)
      • puerto 3307 -> encaminado a replica (lectura)
  • Red: usar la misma red virtual de VMware (Host-only o NAT). En el ejemplo usaré IPs estáticas privadas:
    • db-master: 192.168.56.101
    • db-replica: 192.168.56.102
    • balancer: 192.168.56.103

Recomendación: en VMware crear las 3 VMs clonando la misma instalación de Ubuntu Server 22.04 LTS para facilitar.

2) Preparar la red (ejemplo con IPs estáticas)

En cada VM edita netplan (ajusta el nombre de la interfaz con ip a si no es ens33):

# /etc/netplan/01-netcfg.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    ens33:
      addresses: [192.168.56.101/24]   # cambia por .101/.102/.103 en cada VM
      gateway4: 192.168.100.1          # opcional; usa la que tenga tu red virtual
      nameservers:
        addresses: [8.8.8.8,8.8.4.4]

Luego aplicar:

sudo netplan apply

3) Actualizar y preparar cada VM

En las 3 máquinas:

sudo apt update && sudo apt upgrade -y
sudo apt install -y vim curl wget openssh-server
sudo systemctl enable --now ssh

4) Instalar y configurar MySQL en db-master (192.168.56.101)

  1. Instalar MySQL:
sudo apt install -y mysql-server

2. Editar ajustes importantes (crear archivo /etc/mysql/conf.d/my_custom.cnf para no tocar mucho lo existente). En el master:

# /etc/mysql/conf.d/my_custom.cnf
[mysqld]
bind-address = 0.0.0.0
server-id = 1
report_host=192.168.100.101
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
gtid_mode = ON
enforce_gtid_consistency = ON
master_info_repository = TABLE
relay_log_info_repository = TABLE
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1

3. Reinicia MySQL:

sudo systemctl restart mysql

4. Asegurar instalación / password root (opcional):

sudo mysql_secure_installation

5. Crear usuario para replicación y una base de prueba:

# crear usuario de replicación y BD de prueba
sudo mysql -u root <<SQL
CREATE USER 'repl'@'%' IDENTIFIED BY 'repl_pass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE customers (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50));
INSERT INTO customers (name) VALUES ('Alice'),('Bob');
FLUSH TABLES WITH READ LOCK;  -- bloquea mientras haces dump
SQL

6. Hacer un volcado consistente (con GTID):

sudo mysqldump --all-databases --single-transaction --routines --events --set-gtid-purged=ON -u root -p > /tmp/fulldump.sql
# te pedirá la contraseña de root si la configuraste; si usas auth_socket usa sudo mysqldump ...

7. Desbloquear tablas (en MySQL client si las dejaste bloqueadas):

sudo mysql -u root -e "UNLOCK TABLES;"

Ahora tienes /tmp/fulldump.sql listo para copiar a la réplica.

En MySQL necesitarías replicación multi-maestro replicación bidireccional:
CHANGE MASTER TO 
MASTER_HOST='192.168.100.102',  -- IP de slave 1
MASTER_USER='repl',
MASTER_PASSWORD='tu_password',  -- Asegúrate de usar la contraseña correcta
MASTER_PORT=3306,
MASTER_AUTO_POSITION=1;
-- En la réplica, verifica si está recibiendo datos:
SHOW SLAVE STATUS\G

— Busca estas columnas:
— Slave_IO_Running: Yes
— Slave_SQL_Running: Yes
— Seconds_Behind_Master: 0

5) Instalar MySQL en db-replica (192.168.56.102) y configurarlo

1. Instalar y configurar:

sudo apt install -y mysql-server

2. Configurar /etc/mysql/conf.d/my_custom.cnf en replica con server-id = 2 y variables GTID:

[mysqld]
bind-address = 0.0.0.0
server-id = 2
report_host=192.168.100.102
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
gtid_mode = ON
enforce_gtid_consistency = ON
master_info_repository = TABLE
relay_log_info_repository = TABLE
read_only = 1

replicate-ignore-db=mysql

3. Reiniciar MySQL:

sudo systemctl restart mysql

4. Copiar el dump desde el master (en el master hacer):

scp /tmp/srv1_dump.sql usuario@192.168.100.102:/tmp/

(o usar carpeta compartida/drag&drop si estás en la misma máquina host)

  1. Importar en la réplica:
sudo mysql -u root -p < /tmp/fulldump.sql

6. Conectar la réplica al master usando GTID auto position:

sudo mysql -u root -p -e "CHANGE MASTER TO MASTER_HOST='192.168.56.101', MASTER_USER='repl', MASTER_PASSWORD='repl_pass', MASTER_AUTO_POSITION = 1;"
sudo mysql -u root -p -e "START SLAVE;"

7. Verificar replicación:

sudo mysql -u root -p -e "SHOW SLAVE STATUS\G"
# Verifica: Slave_IO_Running: Yes  y Slave_SQL_Running: Yes

Si ambos son Yes y Seconds_Behind_Master = 0 (o pequeño) → replicación OK.

6) (Opcional pero recomendable) activar semisíncrono en el laboratorio

Semisíncrono reduce riesgo de pérdida de datos: el master esperará la confirmación de al menos un slave.

En el master:

sudo mysql -u root -p -e "INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'; SET GLOBAL rpl_semi_sync_master_enabled = 1;"

En la réplica:

sudo mysql -u root -p -e "INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so'; SET GLOBAL rpl_semi_sync_slave_enabled = 1;"

(En producción pones estas opciones en el archivo de configuración para que se apliquen al reinicio).

7) Instalar HAProxy en la VM balancer (192.168.56.103)

1 Configuración Básica del Balanceador

# Actualizar sistema
sudo apt update && sudo apt upgrade -y

# Instalar herramientas básicas
sudo apt install -y curl wget net-tools tcpdump

2 Instalar HAProxy

# En el balanceador (192.168.100.103)
sudo apt install -y haproxy

# Verificar instalación
haproxy -v

3 Configurar HAProxy para MySQL

  GNU nano 6.2                                                                   /etc/haproxy/haproxy.cfg                                                                            
global
    daemon
    maxconn 4000
    log /dev/log local0

defaults
    mode tcp
    timeout connect 5s
    timeout client 50s
    timeout server 50s
    option tcplog

# Panel de estadísticas
listen stats
    bind 0.0.0.0:8404
    mode http
    stats enable
    stats uri /
    stats refresh 5s
    stats auth admin:Pa$$w0rd

# Balanceador MySQL
listen mysql-balancer
    bind 0.0.0.0:3306
    mode tcp
    balance first
    option tcp-check
    tcp-check connect port 3306

    # Servidores con check básico
    server db-master 192.168.100.101:3306 check inter 2s fall 2 rise 2
    server db-replica1 192.168.100.102:3306 check inter 2s fall 2 rise 2 backup

4 Habilitar y Probar HAProxy

# Habilitar y iniciar HAProxy
sudo systemctl enable haproxy
sudo systemctl start haproxy

# Verificar estado
sudo systemctl status haproxy

# Ver logs en tiempo real (en otra terminal)
sudo tail -f /var/log/haproxy.log

8) Preparar los servidores MYSQL

1 Crear Usuario de Monitoreo en AMBOS MySQL

# En CADA servidor MySQL (101 y 102) ejecutar:
mysql -u root -p

# Ejecutar estos comandos dentro de MySQL:
CREATE USER IF NOT EXISTS 'haproxy_check'@'192.168.100.103' IDENTIFIED BY '';
CREATE USER IF NOT EXISTS 'haproxy_check'@'localhost' IDENTIFIED BY '';
CREATE USER IF NOT EXISTS 'app_user'@'192.168.100.103' IDENTIFIED BY 'AppPassword123!';
CREATE USER IF NOT EXISTS 'app_user'@'localhost' IDENTIFIED BY 'AppPassword123!';

GRANT ALL PRIVILEGES ON *.* TO 'app_user'@'192.168.100.103';
GRANT ALL PRIVILEGES ON *.* TO 'app_user'@'localhost';
FLUSH PRIVILEGES;

2 Verificar que MySQL Acepte Conexiones Externas

# En CADA servidor MySQL, verificar:
sudo grep bind-address /etc/mysql/mysql.conf.d/mysqld.cnf

# Si no es 0.0.0.0, cambiarlo:
sudo sed -i 's/^bind-address.*/bind-address = 0.0.0.0/' /etc/mysql/mysql.conf.d/mysqld.cnf
sudo systemctl restart mysql

9) Probar la configuración

1 Probar Conexiones desde el Balanceador

# Desde el balanceador (103), probar conexiones directas:
telnet 192.168.100.101 3306
telnet 192.168.100.102 3306

# Probar usuarios MySQL
mysql -h 192.168.100.101 -u app_user -pAppPassword123! -e "SELECT @@hostname;"
mysql -h 192.168.100.102 -u app_user -pAppPassword123! -e "SELECT @@hostname;"

2 Probar HAProxy

# Probar cada puerto del balanceador:

# Solo escrituras (maestro)
mysql -h 127.0.0.1 -P 3306 -u app_user -pAppPassword123! -e "SELECT @@hostname as 'Escrituras';"

# Solo lecturas (esclavo)  
mysql -h 127.0.0.1 -P 3307 -u app_user -pAppPassword123! -e "SELECT @@hostname as 'Lecturas';"

# Balanceo automático
mysql -h 127.0.0.1 -P 3308 -u app_user -pAppPassword123! -e "SELECT @@hostname as 'Auto-Balanceo';"

3 Ver Panel de Monitoreo

# Abrir en navegador web:
echo "Panel de monitoreo: http://192.168.100.103:8404/monitor

Accede a: http://192.168.100.103:8404
Usuario: admin
Password: AdminPassword123!

lineas importantes

 Verificar firewall

# En el maestro
sudo ufw status
sudo ufw allow 3306
# o en CentOS/RHEL
sudo firewall-cmd --list-all
sudo firewall-cmd --add-port=3306/tcp --permanent

Reinicia servicios después de cambios:

# En el maestro
sudo systemctl restart mysql

# En la réplica, reinicia la replicación
STOP SLAVE;
START SLAVE;
#Verifica nuevamente:
SHOW SLAVE STATUS\G

Verificar Estado de HAProxy

# Verificar si HAProxy está corriendo
sudo systemctl status haproxy

# Si no está activo, iniciarlo
sudo systemctl start haproxy
sudo systemctl enable haproxy

# Ver logs de error
sudo journalctl -u haproxy -f

# Verificar que HAProxy está escuchando en los puertos
sudo netstat -tlnp | grep haproxy

# Verificar específicamente puerto 3306 y 8404
sudo ss -tlnp | grep ':3306\|:8404'

Verificar Configuración HAProxy

# Verificar sintaxis del archivo de configuración
sudo haproxy -c -f /etc/haproxy/haproxy.cfg

# Ver contenido actual del archivo
sudo cat /etc/haproxy/haproxy.cfg

VERIFICAR QUE HAPROXY ESTÉ EJECUTÁNDOSE

# Verificar procesos
ps aux | grep haproxy

# Verificar puertos abiertos
sudo netstat -tlnp | grep haproxy

# Verificar que escucha en los puertos
sudo ss -tlnp | grep haproxy

VERIFICAR CONEXIÓN DIRECTA A MYSQL

# Desde el balanceador (103), probar conexión directa a MySQL
echo "=== PROBANDO CONEXIÓN DIRECTA A MYSQL ==="

# Probar conexión al maestro
mysql -h 192.168.100.101 -u app_user -pAppPassword123! -e "SELECT @@hostname as 'Master';"

# Probar conexión al esclavo
mysql -h 192.168.100.102 -u app_user -pAppPassword123! -e "SELECT @@hostname as 'Slave';"

# Probar usuario de check
mysql -h 192.168.100.101 -u haproxy_check -e "SELECT 1 as 'Check_OK';" 2>/dev/null && echo "✅ Check user funciona en 101" || echo "❌ Check user falla en 101"
mysql -h 192.168.100.102 -u haproxy_check -e "SELECT 1 as 'Check_OK';" 2>/dev/null && echo "✅ Check user funciona en 102" || echo "❌ Check user falla en 102"

VERIFICACIÓN FINAL

# Script de verificación completo
cat > verificar_todo.sh << 'EOF'
#!/bin/bash
echo "=== VERIFICACIÓN COMPLETA DEL SISTEMA ==="

echo "1. Estado de HAProxy:"
sudo systemctl status haproxy --no-pager -l

echo -e "\n2. Puertos abiertos por HAProxy:"
sudo netstat -tlnp | grep haproxy || echo "HAProxy no está escuchando en puertos"

echo -e "\n3. Procesos HAProxy:"
ps aux | grep haproxy | grep -v grep

echo -e "\n4. Verificar conexión MySQL directa:"
for host in 192.168.100.101 192.168.100.102; do
    echo -n "MySQL $host: "
    timeout 3 mysql -h $host -u app_user -pAppPassword123! -e "SELECT 1;" &>/dev/null && echo "✅ OK" || echo "❌ FALLO"
done

echo -e "\n5. Probar HAProxy:"
echo -n "HAProxy puerto 3306: "
timeout 3 mysql -h 127.0.0.1 -P 3306 -u app_user -pAppPassword123! -e "SELECT 1;" &>/dev/null && echo "✅ OK" || echo "❌ FALLO"

echo -e "\n6. Panel web:"
echo "http://192.168.100.103:8404/"

echo -e "\n7. Logs recientes de HAProxy:"
sudo tail -10 /var/log/haproxy.log 2>/dev/null || echo "No hay logs disponibles"

echo "=== VERIFICACIÓN COMPLETADA ==="
EOF

chmod +x verificar_todo.sh
./verificar_todo.sh
 Verificar que el balanceador distribuye desde cliente 
mysql -h 192.168.100.103 -u app_user -pAppPassword123! -e "SELECT @@hostname, NOW()"

PRUEBAS DE FALLOVER

Simular caída del maestro

En db-master:
sudo systemctl stop mysql

comprobar desde cliente

mysql -h 192.168.100.103 -u app_user -pAppPassword123! -e "SELECT @@hostname, NOW()"

Las conexiones deberían ir automáticamente a slave1

reiniciar el maestro

sudo systemctl restart mysql

comprobar desde cliente

debe mostrarle el master

mysql -h 192.168.100.103 -u app_user -pAppPassword123! -e "SELECT @@hostname, NOW()"
mysql -h 192.168.100.103 -P 3306 -u app_user -pAppPassword123! -e "SELECT @@hostname;"

Comprobar master y replica

Master

SHOW MASTER STATUS;

Replica

SHOW SLAVE STATUS\G

Ver binlogs actuales

SHOW BINARY LOGS;

En ambos server mysql, aumenta el tiempo de expiración de binlogs:

SET GLOBAL binlog_expire_logs_seconds = 2592000;  -- 30 días
-- O en my.cnf: binlog_expire_logs_seconds = 2592000

Si la conectividad falla, verificar:

A. Firewall:

# En los servidores MySQL
sudo ufw status
sudo ufw allow from 192.168.100.103 to any port 3306

# O en CentOS/RHEL
sudo firewall-cmd --list-all
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="192.168.100.103" port port="3306" protocol="tcp" accept' --permanent

B. Bind address en MySQL:

-- En los servidores MySQL
SHOW VARIABLES LIKE 'bind_address';

-- Si es 127.0.0.1, cambiar a 0.0.0.0 o la IP específica
-- Editar /etc/mysql/my.cnf:
-- bind-address = 0.0.0.0

C. Configuración alternativa si persisten problemas:

listen mysql-balancer
    bind 0.0.0.0:3306
    mode tcp
    balance first
    timeout client 90s
    timeout server 90s
    
    # Sin health checks complejos
    server db-master 192.168.100.102:3306 check port 3306
    server db-replica1 192.168.100.101:3306 check port 3306 backup

  Aplicar cambios:

# Verificar sintaxis
sudo haproxy -c -f /etc/haproxy/haproxy.cfg

# Reiniciar HAProxy
sudo systemctl restart haproxy

# Verificar estado
sudo systemctl status haproxy
echo "show stat" | sudo socat stdio /var/run/haproxy/admin.sock

Probar conectividad básica primero:

# ¿Puede el HAProxy conectar a MySQL directamente?
mysql -h 192.168.100.102 -P 3306 -u app_user -pAppPassword123! -e "SELECT @@hostname"