Este post está disponible en: English
Percona XtraDB Cluster, comúnmente conocido como PXC, es una solución de alta disponibilidad para MySQL basada en Percona Server y Galera Cluster.
A diferencia de una arquitectura tradicional de MySQL con un nodo primario y réplicas, en Percona XtraDB Cluster todos los nodos mantienen una copia completa de la base de datos y participan en el estado del clúster.
Esto convierte a PXC en una excelente plataforma para practicar conceptos relacionados con DevOps, Site Reliability Engineering y Database Reliability Engineering, especialmente en escenarios donde necesitamos alta disponibilidad, recuperación ante fallos, mantenimiento sin downtime y consistencia entre nodos.
En este artículo construiremos un laboratorio de tres nodos de Percona XtraDB Cluster y, más importante aún, aprenderemos qué sucede cuando un nodo falla, se pierde el quorum, una réplica queda atrasada o existe una partición de red.
El objetivo no es solamente instalar Percona.
El objetivo es construir un entorno donde podamos romper cosas deliberadamente y entender cómo se comporta el clúster.
Arquitectura de Percona XtraDB Cluster
Una arquitectura básica de PXC puede verse así:
Aplicación | HAProxy | +---------+---------+ | | | PXC01 PXC02 PXC03 MySQL MySQL MySQL \ | / \----- Galera ----/Cada nodo contiene una copia completa de la base de datos.
Esto es diferente de una arquitectura tradicional de MySQL:
Primario | | replicación asíncrona vRéplicaEn PXC, las transacciones se replican utilizando el mecanismo de write-set replication de Galera.
Aunque Percona XtraDB Cluster permite ejecutar escrituras en distintos nodos, esto no significa necesariamente que una aplicación deba distribuir todas las escrituras de forma aleatoria.
Una arquitectura común consiste en tener un nodo preferido para escritura y utilizar los demás como respaldo y failover:
HAProxy / ProxySQL | Escrituras | PXC01 / \ PXC02 PXC03Esto reduce la posibilidad de conflictos de certificación entre transacciones concurrentes.
Cómo funciona una transacción en PXC
Supongamos que una aplicación ejecuta la siguiente operación en pxc01:
BEGIN; UPDATE accountsSET balance = balance - 100WHERE id = 10; COMMIT;La transacción primero se ejecuta localmente.
Antes de confirmar el cambio, Galera crea un write-set que contiene la información necesaria para replicar esa modificación al resto del clúster.
De forma simplificada:
PXC01 |La transacción se ejecuta | vSe genera un write-set | +------------+ | | v vPXC02 PXC03 | |Certificación Certificación \ / \----------/ | COMMITCada nodo realiza un proceso llamado certificación.
La certificación permite determinar si otra transacción concurrente modificó los mismos registros.
Por ejemplo:
PXC01 PXC02 UPDATE users UPDATE usersSET name='Alice' SET name='Bob'WHERE id=10 WHERE id=10 \ / \ / Certificación | Conflicto detectado | Una transacción abortaEsta es una de las razones por las que el soporte multi-primary debe utilizarse con cuidado.
Si múltiples nodos realizan muchas escrituras simultáneas sobre los mismos datos, pueden aumentar los conflictos de certificación.
Por qué un clúster PXC debería tener tres nodos
Uno de los conceptos más importantes en Galera es el quorum.
Consideremos un clúster de tres nodos:
PXC01 ---- PXC02 ---- PXC03 1 1 1Para continuar operando de forma segura, el clúster necesita mantener una mayoría de nodos disponibles.
Con tres nodos:
3 nodos disponibles → hay quorum2 nodos disponibles → hay quorum1 nodo disponible → no hay quorumSi un nodo falla:
PXC01 -------- PXC02 X PXC03Los dos nodos restantes representan la mayoría del clúster, por lo que el servicio continúa funcionando.
Sin embargo, si también falla pxc02:
PXC01 X PXC02X PXC03pxc01 queda aislado y ya no tiene quorum.
En ese escenario podemos encontrar estados como:
wsrep_cluster_status = Non-Primarywsrep_ready = OFFAunque el proceso de MySQL siga corriendo, el nodo ya no debe considerarse saludable para tráfico de aplicación.
Este comportamiento ayuda a prevenir uno de los problemas más peligrosos en sistemas distribuidos:
split brain.
Sin protección por quorum, dos partes separadas de un clúster podrían creer que son la copia autoritativa de la base de datos y aceptar escrituras diferentes.
IST y SST
Cuando un nodo permanece offline durante cierto tiempo, necesita sincronizarse antes de volver a participar normalmente en el clúster.
Supongamos que inicialmente tenemos:
PXC01 PXC02 PXC03 ✓ ✓ ✓Después pxc03 falla:
PXC01 PXC02 PXC03 ✓ ✓ XMientras pxc03 está fuera, las aplicaciones continúan generando transacciones.
Cuando el nodo regresa, debe actualizar su estado.
Existen dos mecanismos principales para hacerlo.
Incremental State Transfer — IST
Si otro nodo conserva en su GCache las transacciones que pxc03 perdió, únicamente se envían esos cambios.
PXC01 GCache TX1001TX1002TX1003TX1004TX1005 | | transacciones faltantes v PXC03Esto se conoce como:
Incremental State Transfer o IST.
IST normalmente es rápido porque solamente replica las transacciones faltantes.
State Snapshot Transfer — SST
Si el nodo estuvo offline demasiado tiempo y las transacciones necesarias ya no existen en GCache, será necesario transferir una copia completa del estado de la base de datos.
PXC01 Base de datos completa | | v PXC03Este proceso se conoce como:
State Snapshot Transfer o SST.
Un SST puede consumir considerablemente más recursos que un IST, especialmente:
CPUDiscoI/ORedTiempoPor eso es importante entender conceptos como:
ISTSSTGCacheDonorJoinercuando se administra un clúster PXC.
Diseño del laboratorio
Para este laboratorio utilizaremos cuatro máquinas virtuales:
Servidor Dirección IP Propósito pxc01 192.168.50.11 Nodo Perconapxc02 192.168.50.12 Nodo Perconapxc03 192.168.50.13 Nodo Perconamysql-proxy 192.168.50.10 HAProxyPara cada nodo de base de datos podemos utilizar:
2 vCPU4 GB RAM30–50 GB de discoUbuntu 24.04Utilizar máquinas virtuales en lugar de contenedores tiene una ventaja importante para este laboratorio: podemos reproducir fallos de infraestructura más realistas.
Por ejemplo:
Particiones de redCaídas de VMDisco llenoProblemas de firewallLatencia de almacenamientoReinicios del sistema operativoPuertos necesarios
Los nodos PXC utilizan varios puertos para comunicarse:
3306 conexiones MySQL4444 State Snapshot Transfer4567 replicación Galera4568 Incremental State TransferSi utilizamos UFW:
sudo ufw allow 3306/tcpsudo ufw allow 4444/tcpsudo ufw allow 4567/tcpsudo ufw allow 4567/udpsudo ufw allow 4568/tcpEn un ambiente real, estas reglas deberían limitarse únicamente a la red donde viven los nodos del clúster.
Configurar los hostnames
En el primer nodo:
sudo hostnamectl set-hostname pxc01En el segundo:
sudo hostnamectl set-hostname pxc02En el tercero:
sudo hostnamectl set-hostname pxc03Después agregamos los nodos a /etc/hosts:
192.168.50.11 pxc01192.168.50.12 pxc02192.168.50.13 pxc03Antes de continuar, debemos verificar que todos los nodos puedan comunicarse entre sí.
Instalar Percona XtraDB Cluster
Ejecutaremos el proceso de instalación en los tres nodos.
sudo apt updateInstalamos algunas dependencias:
sudo apt install -y \ wget \ gnupg2 \ lsb-release \ curlDescargamos el repositorio de Percona:
wget https://repo.percona.com/apt/percona-release_latest.generic_all.debLo instalamos:
sudo dpkg -i percona-release_latest.generic_all.debHabilitamos el repositorio de PXC:
sudo percona-release setup pxc-84-ltsActualizamos la información de paquetes:
sudo apt updateInstalamos Percona XtraDB Cluster:
sudo apt install -y percona-xtradb-clusterUna vez instalado, detenemos MySQL en los tres nodos:
sudo systemctl stop mysqlAhora podemos configurar el clúster.
Configurar PXC01
Primero revisamos dónde se encuentran los archivos de configuración:
ls -la /etc/mysql/ls -la /etc/mysql/mysql.conf.d/Creamos:
sudo nano /etc/mysql/mysql.conf.d/pxc.cnfPara pxc01:
[mysqld] server-id=1 datadir=/var/lib/mysqluser=mysql default_storage_engine=InnoDBinnodb_autoinc_lock_mode=2 wsrep_provider=/usr/lib/libgalera_smm.so wsrep_cluster_name=pxc-lab wsrep_cluster_address=gcomm://192.168.50.11,192.168.50.12,192.168.50.13 wsrep_node_name=pxc01wsrep_node_address=192.168.50.11 wsrep_sst_method=cloneLos parámetros más importantes son:
wsrep_cluster_namewsrep_cluster_addresswsrep_node_namewsrep_node_addressConfigurar PXC02
En el segundo nodo:
[mysqld] server-id=2 datadir=/var/lib/mysqluser=mysql default_storage_engine=InnoDBinnodb_autoinc_lock_mode=2 wsrep_provider=/usr/lib/libgalera_smm.so wsrep_cluster_name=pxc-lab wsrep_cluster_address=gcomm://192.168.50.11,192.168.50.12,192.168.50.13 wsrep_node_name=pxc02wsrep_node_address=192.168.50.12 wsrep_sst_method=cloneConfigurar PXC03
Finalmente:
[mysqld] server-id=3 datadir=/var/lib/mysqluser=mysql default_storage_engine=InnoDBinnodb_autoinc_lock_mode=2 wsrep_provider=/usr/lib/libgalera_smm.so wsrep_cluster_name=pxc-lab wsrep_cluster_address=gcomm://192.168.50.11,192.168.50.12,192.168.50.13 wsrep_node_name=pxc03wsrep_node_address=192.168.50.13 wsrep_sst_method=cloneBootstrap del clúster
El primer nodo debe arrancarse de manera diferente.
En pxc01:
sudo systemctl start mysql@bootstrapCon esto indicamos que este nodo está creando el Primary Component inicial del clúster.
Nos conectamos:
mysql -uroot -pY revisamos:
SHOW STATUS LIKE 'wsrep_cluster_size'; SHOW STATUS LIKE 'wsrep_cluster_status'; SHOW STATUS LIKE 'wsrep_local_state_comment'; SHOW STATUS LIKE 'wsrep_ready';Un nodo saludable debería mostrar:
wsrep_cluster_size 1wsrep_cluster_status Primarywsrep_local_state_comment Syncedwsrep_ready ONAgregar PXC02
En el segundo nodo iniciamos MySQL normalmente:
sudo systemctl start mysqlPodemos seguir los logs con:
journalctl -u mysql -fCuando termine la sincronización:
SHOW STATUS LIKE 'wsrep_cluster_size';Deberíamos obtener:
2Y:
SHOW STATUS LIKE 'wsrep_local_state_comment';Debería mostrar:
SyncedAgregar PXC03
En el tercer nodo:
sudo systemctl start mysqlVerificamos nuevamente:
SHOW STATUS LIKE 'wsrep_cluster_size';Ahora deberíamos obtener:
3También verificamos:
SHOW STATUS LIKE 'wsrep_cluster_status';El resultado esperado es:
PrimaryNuestro clúster de tres nodos ya está funcionando.
Probar la replicación
En pxc01 creamos una base de datos:
CREATE DATABASE dbre_lab; USE dbre_lab;Después una tabla:
CREATE TABLE transactions ( id BIGINT PRIMARY KEY AUTO_INCREMENT, description VARCHAR(255), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);Insertamos un registro:
INSERT INTO transactions(description)VALUES ('Insertado desde pxc01');Ahora nos conectamos a pxc02:
SELECT *FROM dbre_lab.transactions;El registro debería existir.
Después insertamos desde pxc02:
INSERT INTO dbre_lab.transactions(description)VALUES ('Insertado desde pxc02');Finalmente consultamos desde pxc03:
SELECT *FROM dbre_lab.transactions;Ambos registros deberían aparecer.
Métricas WSREP importantes
Podemos obtener todas las métricas usando:
SHOW STATUS LIKE 'wsrep%';Sin embargo, para troubleshooting cotidiano es mejor enfocarse en algunas variables:
SHOW STATUS WHERE Variable_name IN ( 'wsrep_cluster_size', 'wsrep_cluster_status', 'wsrep_connected', 'wsrep_ready', 'wsrep_local_state_comment', 'wsrep_local_recv_queue', 'wsrep_flow_control_paused', 'wsrep_local_cert_failures', 'wsrep_local_bf_aborts');Un clúster saludable de tres nodos debería aproximarse a:
wsrep_cluster_size 3wsrep_cluster_status Primarywsrep_connected ONwsrep_ready ONwsrep_local_state_comment SyncedEstas métricas deberían formar parte de cualquier sistema de monitoreo del clúster.
Ejercicio 1: perder un nodo
Detenemos pxc03:
sudo systemctl stop mysqlDesde otro nodo:
SHOW STATUS LIKE 'wsrep_cluster_size';El resultado debería ser:
2Todavía tenemos quorum.
Probamos una escritura:
INSERT INTO dbre_lab.transactions(description)VALUES ('Transacción con PXC03 fuera de servicio');La operación debería completarse correctamente.
Después levantamos nuevamente el nodo:
sudo systemctl start mysqlY observamos:
journalctl -u mysql -fEjercicio 2: observar un IST
Detenemos nuevamente pxc03:
sudo systemctl stop mysqlGeneramos algunas transacciones en pxc01:
INSERT INTO dbre_lab.transactions(description)VALUES ('PXC03 está offline');Después iniciamos nuevamente pxc03:
sudo systemctl start mysqlRevisamos:
journalctl -u mysqlY buscamos referencias a:
ISTSi las transacciones necesarias todavía existen en GCache, el nodo podrá recuperar únicamente los cambios que perdió.
Ejercicio 3: forzar un SST
Ahora podemos intentar que IST no sea posible.
La estrategia es:
1. Detener PXC032. Generar una gran cantidad de datos3. Superar el espacio disponible en GCache4. Iniciar nuevamente PXC03El nodo debería necesitar un State Snapshot Transfer completo.
Durante este ejercicio conviene monitorear:
Duración del SSTCPUI/O de discoTráfico de redCarga sobre el donorEstado del joinerLatencia de aplicaciónEjercicio 4: perder el quorum
Comenzamos con:
PXC01 ✓PXC02 ✓PXC03 ✓Detenemos pxc02:
sudo systemctl stop mysqlTodavía tenemos quorum.
Después detenemos pxc03:
sudo systemctl stop mysqlAhora solamente queda pxc01.
Consultamos:
SHOW STATUS LIKE 'wsrep_cluster_status'; SHOW STATUS LIKE 'wsrep_ready';Este ejercicio demuestra algo importante:
MySQL está ejecutándoseno significa necesariamente que:
La base de datos está lista para recibir tráficoUn nodo que perdió quorum no debería considerarse saludable.
Ejercicio 5: crear una partición de red
También podemos simular problemas de comunicación.
Por ejemplo, podemos bloquear temporalmente el tráfico de Galera:
sudo iptables -A INPUT -p tcp --dport 4567 -j DROPsudo iptables -A OUTPUT -p tcp --dport 4567 -j DROPDespués observamos:
SHOW STATUS LIKE 'wsrep%';En particular:
wsrep_cluster_sizewsrep_cluster_statuswsrep_connectedwsrep_readyPara revertir:
sudo iptables -D INPUT -p tcp --dport 4567 -j DROPsudo iptables -D OUTPUT -p tcp --dport 4567 -j DROPEste escenario ayuda a comprender que una caída de proceso y una partición de red son eventos muy diferentes.
Agregar HAProxy
Nuestro siguiente paso es evitar que las aplicaciones se conecten directamente a un nodo específico.
La arquitectura puede evolucionar a:
Aplicación | v +---------------+ | HAProxy | | 192.168.50.10 | +-------+-------+ | +------------+------------+ | | | v v v +-------+ +-------+ +-------+ | PXC01 | | PXC02 | | PXC03 | +-------+ +-------+ +-------+Instalamos HAProxy:
sudo apt updatesudo apt install -y haproxyAquí existe una consideración muy importante.
Comprobar únicamente que el puerto 3306 esté abierto no es suficiente.
Podemos tener:
mysqld ejecutándose3306 escuchandopero al mismo tiempo:
wsrep_ready = OFFEse nodo no debería recibir tráfico.
Por eso el health check debería ser consciente del estado de PXC y no limitarse a verificar conectividad TCP.
Monitorear el clúster
El siguiente paso natural es agregar monitoreo.
Percona Monitoring and Management, conocido como PMM, es una opción excelente para este laboratorio.
La arquitectura final podría verse así:
Aplicación | HAProxy | +------------+------------+ | | | PXC01 PXC02 PXC03 | | | +------------+------------+ | PMMAlgunas métricas importantes son:
CPUMemoriaLatencia de discoBuffer poolConexionesLatencia de queriesSlow queriesFlow controlReplication queuesErrores de certificaciónSSTISTParticularmente:
wsrep_local_recv_queuewsrep_flow_control_pausedwsrep_local_cert_failureswsrep_local_bf_abortspueden ofrecernos mucha más información que simplemente revisar si MySQL está activo.
Convertir el laboratorio en un entorno de práctica DBRE
Instalar Percona solamente es el primer paso.
El verdadero aprendizaje comienza cuando operamos y rompemos el clúster.
Una buena ruta de aprendizaje sería:
Etapa 1 — Build
Construir los tres nodos manualmente.
Entender cada parámetro antes de automatizarlo.
Etapa 2 — Operate
Agregar:
HAProxyProxySQLPMMBackupsMonitoringAlertasEtapa 3 — Break
Simular:
Falla de nodoFalla de VMPartición de redDisco llenoAlta latenciaError de firewallError de configuraciónEtapa 4 — Recover
Practicar:
ISTSSTRecuperación de quorumReemplazo de nodoRecuperación completa del clústerEtapa 5 — Maintain
Practicar:
Rolling restartsActualizaciones del sistema operativoUpgrades de base de datosCambios de configuraciónRotación de certificadossin generar downtime completo.
Etapa 6 — Automate
Después de entender el proceso manual, reconstruir todo utilizando herramientas como:
TerraformAnsibleGitHub ActionsLa infraestructura debería poder ser creada nuevamente desde cero.
Etapa 7 — Observe
Crear dashboards y alertas para:
Estado WSREPFlow controlConflictos de certificaciónSincronizaciónLatenciaI/O de discoSSTISTEtapa 8 — Document
Finalmente crear runbooks reales.
Por ejemplo:
Nodo PXC caídoClúster Non-PrimaryNodo no puede unirse al clústerSST bloqueadoDisco llenoFlow control elevadoRolling restartRolling upgradeCaída completa del clústerRecuperación completa del clúster
Existe un escenario especialmente importante:
los tres nodos están apagados.
PXC01 XPXC02 XPXC03 XNo deberíamos elegir un nodo al azar y realizar el bootstrap.
Cada nodo puede contener una posición de Galera diferente dependiendo de las últimas transacciones que alcanzó a procesar.
Durante la recuperación podemos utilizar:
mysqld --wsrep-recoverpara investigar la posición de cada nodo.
El objetivo es identificar el nodo con el estado más avanzado y confiable antes de iniciar nuevamente el Primary Component.
Elegir un nodo con un estado más antiguo podría provocar pérdida de transacciones.
Por esta razón, la recuperación completa de un clúster debería ser uno de los ejercicios principales de cualquier laboratorio PXC.
Qué podemos aprender con este laboratorio
Un laboratorio de Percona XtraDB Cluster permite estudiar mucho más que la instalación de MySQL.
Podemos experimentar directamente con conceptos de sistemas distribuidos como:
QuorumConsistenciaWrite-set replicationCertificación de transaccionesPrevención de split brainReplicación síncronaFailure domainsState synchronizationFlow controlFailoverTambién refuerza una idea fundamental de Reliability Engineering:
Que el proceso de MySQL esté ejecutándose no significa que el servicio de base de datos esté saludable.
Un servidor puede tener MySQL activo y el puerto 3306 disponible, pero estar desconectado del Primary Component o no encontrarse en condiciones seguras para procesar tráfico.
Por eso la observabilidad, los health checks, el quorum y los mecanismos de recuperación son componentes fundamentales de una plataforma de bases de datos altamente disponible.
Conclusión
Percona XtraDB Cluster es una excelente plataforma para aprender cómo funcionan los ambientes MySQL altamente disponibles.
Un laboratorio de tres nodos nos permite experimentar de forma segura con escenarios que serían demasiado riesgosos para reproducir directamente en producción.
Después de completar la instalación, el siguiente paso debería ser romper el clúster deliberadamente.
Detén un nodo.
Corta la comunicación de red.
Fuerza un SST.
Pierde el quorum.
Llena el disco.
Reinicia todos los servidores.
Recupera el clúster.
Después automatiza el proceso y vuelve a repetirlo.
El objetivo no es solamente aprender a instalar Percona.
El objetivo es comprender qué sucede cuando la infraestructura de base de datos deja de comportarse de la manera que esperamos.
Ahí es donde este laboratorio comienza a convertirse en una verdadera práctica de Database Reliability Engineering.
Comentarios