MySQL Group Replication es el mecanismo de alta disponibilidad integrado en MySQL. Varios servidores forman un grupo que acuerda el orden de cada transacción mediante un protocolo de consenso, de modo que todos aplican los mismos cambios en el mismo orden. En modo primario único, un miembro acepta escrituras y el resto son réplicas de solo lectura; si el primario cae, el grupo elige otro automáticamente.
En este tutorial configurarás un grupo de tres nodos con MySQL 8.0 desde los repositorios de Ubuntu 24.04, en modo primario único. Comprobarás la replicación, provocarás un failover, cambiarás el primario a mano y verás cómo añadir y retirar miembros.
Requisitos previos
- Tres servidores con Ubuntu 24.04 LTS, por ejemplo VPS de CubePath, con al menos 2 GB de RAM y un usuario no root con
sudo. - Red privada con baja latencia entre ellos. Cada transacción necesita el acuerdo de la mayoría del grupo antes de confirmarse.
- Tres miembros como mínimo (el grupo tolera la caída de uno) y nueve como máximo.
Valores usados en los ejemplos:
| Nodo | IP privada |
|---|---|
mysql1 | 10.0.0.11 |
mysql2 | 10.0.0.12 |
mysql3 | 10.0.0.13 |
Puertos entre nodos:
| Puerto | Uso |
|---|---|
| 3306/tcp | Clientes y recuperación de datos entre miembros |
| 33061/tcp | Comunicación interna del grupo |
Paso 1: Instalar MySQL en los tres nodos
Ejecuta en cada nodo:
sudo apt update
sudo apt install mysql-server
Comprueba la versión y que el plugin de Group Replication está disponible:
mysql --version
ls /usr/lib/mysql/plugin/group_replication.so
mysql Ver 8.0.43-0ubuntu0.24.04.1 for Linux on x86_64 ((Ubuntu))
/usr/lib/mysql/plugin/group_replication.so
Abre los puertos solo para la red privada:
sudo ufw allow from 10.0.0.0/24 to any port 3306,33061 proto tcp
Paso 2: Configurar cada servidor para Group Replication
Genera un UUID que identificará al grupo. Hazlo una sola vez y usa el mismo valor en los tres nodos:
cat /proc/sys/kernel/random/uuid
aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee
MySQL en Ubuntu lee los ficheros de /etc/mysql/mysql.conf.d/ en orden alfabético, y los posteriores prevalecen. Crea un fichero que se cargue después de mysqld.cnf para que su bind-address sustituya al valor por defecto (127.0.0.1). En mysql1:
sudo nano /etc/mysql/mysql.conf.d/zz-group-replication.cnf
[mysqld]
# Identidad del servidor
server_id = 1
bind-address = 0.0.0.0
report_host = 10.0.0.11
# Requisitos de Group Replication
gtid_mode = ON
enforce_gtid_consistency = ON
disabled_storage_engines = "MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
# Plugin y grupo
plugin_load_add = group_replication.so
group_replication_group_name = "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee"
group_replication_start_on_boot = OFF
group_replication_local_address = "10.0.0.11:33061"
group_replication_group_seeds = "10.0.0.11:33061,10.0.0.12:33061,10.0.0.13:33061"
group_replication_bootstrap_group = OFF
# Cifrado del tráfico del grupo y de la recuperación
group_replication_ssl_mode = REQUIRED
group_replication_recovery_use_ssl = ON
Qué hace cada bloque:
server_iddebe ser distinto en cada nodo.report_hostes la dirección con la que el miembro se anuncia al resto; usar la IP evita depender de la resolución de nombres.- Group Replication exige GTID e InnoDB.
disabled_storage_enginesimpide crear por error tablas en motores que no se replican. El log binario, el formatoROWylog_replica_updatesya vienen activos por defecto en MySQL 8.0. group_replication_group_seedsson los miembros a los que un nodo intenta conectarse para unirse.group_replication_local_addresses la dirección de este nodo para la comunicación interna (puerto 33061, distinto del 3306).group_replication_start_on_boot = OFFevita que el nodo intente unirse antes de que el grupo exista. Lo activarás en el paso 7.- Las dos opciones de SSL usan los certificados que MySQL genera automáticamente al instalarse, suficiente para cifrar el tráfico dentro de una red privada.
En mysql2 y mysql3 crea el mismo fichero cambiando solo estas tres líneas:
# En mysql2
server_id = 2
report_host = 10.0.0.12
group_replication_local_address = "10.0.0.12:33061"
# En mysql3
server_id = 3
report_host = 10.0.0.13
group_replication_local_address = "10.0.0.13:33061"
Reinicia MySQL en cada nodo y comprueba que el plugin está activo:
sudo systemctl restart mysql
sudo mysql -e "SELECT PLUGIN_NAME, PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication';"
+-------------------+---------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+-------------------+---------------+
| group_replication | ACTIVE |
+-------------------+---------------+
Paso 3: Crear el usuario de recuperación
Cuando un miembro se une, copia de otro las transacciones que le faltan a través del canal group_replication_recovery, con un usuario de replicación. Créalo en cada nodo con el log binario desactivado para esta sesión, de modo que la creación del usuario no genere transacciones locales distintas en cada servidor:
sudo mysql
SET SQL_LOG_BIN = 0;
CREATE USER 'rpl_user'@'%' IDENTIFIED BY 'your_strong_password';
GRANT REPLICATION SLAVE, CONNECTION_ADMIN, BACKUP_ADMIN, GROUP_REPLICATION_STREAM ON *.* TO 'rpl_user'@'%';
SET SQL_LOG_BIN = 1;
CHANGE REPLICATION SOURCE TO
SOURCE_USER = 'rpl_user',
SOURCE_PASSWORD = 'your_strong_password'
FOR CHANNEL 'group_replication_recovery';
EXIT;
Usa la misma contraseña en los tres nodos y sustituye your_strong_password por una segura.
Paso 4: Arrancar el grupo en el primer nodo
El primer miembro debe crear el grupo (bootstrap). Esto se hace solo en un nodo y solo una vez; después se desactiva para que no pueda crear un segundo grupo por accidente. En mysql1:
sudo mysql
SET GLOBAL group_replication_bootstrap_group = ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group = OFF;
SELECT MEMBER_HOST, MEMBER_STATE, MEMBER_ROLE
FROM performance_schema.replication_group_members;
+-------------+--------------+-------------+
| MEMBER_HOST | MEMBER_STATE | MEMBER_ROLE |
+-------------+--------------+-------------+
| 10.0.0.11 | ONLINE | PRIMARY |
+-------------+--------------+-------------+
Paso 5: Unir los otros dos nodos
En mysql2 y después en mysql3:
sudo mysql -e "START GROUP_REPLICATION;"
El nodo pasa por el estado RECOVERING mientras copia las transacciones que le faltan y después queda ONLINE. Comprueba el grupo desde cualquier miembro:
sudo mysql -e "SELECT MEMBER_HOST, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members;"
+-------------+--------------+-------------+
| MEMBER_HOST | MEMBER_STATE | MEMBER_ROLE |
+-------------+--------------+-------------+
| 10.0.0.11 | ONLINE | PRIMARY |
| 10.0.0.12 | ONLINE | SECONDARY |
| 10.0.0.13 | ONLINE | SECONDARY |
+-------------+--------------+-------------+
Paso 6: Probar la replicación
En el primario (mysql1), crea una base de datos y una tabla. Group Replication exige que todas las tablas tengan clave primaria:
sudo mysql -e "CREATE DATABASE gr_test; CREATE TABLE gr_test.t (id INT PRIMARY KEY, origen VARCHAR(20)); INSERT INTO gr_test.t VALUES (1, 'mysql1');"
Léela en un secundario (mysql3):
sudo mysql -e "SELECT * FROM gr_test.t;"
+----+--------+
| id | origen |
+----+--------+
| 1 | mysql1 |
+----+--------+
Intenta escribir en el secundario. Debe fallar, porque en modo primario único los secundarios se ponen en super_read_only:
sudo mysql -e "INSERT INTO gr_test.t VALUES (2, 'mysql3');"
ERROR 1290 (HY000) at line 1: The MySQL server is running with the --super-read-only option so it cannot execute this statement
Paso 7: Unirse automáticamente al arrancar
Ahora que el grupo existe, activa group_replication_start_on_boot para que un nodo que se reinicie vuelva a unirse solo. En cada nodo, cambia la línea en /etc/mysql/mysql.conf.d/zz-group-replication.cnf:
group_replication_start_on_boot = ON
El cambio se aplicará en el próximo reinicio de cada nodo; no hace falta reiniciar ahora.
Importantesi los tres nodos se paran a la vez, ninguno encontrará un grupo al que unirse. En ese caso hay que repetir el bootstrap del paso 4 en el nodo con más transacciones aplicadas (compara
SELECT @@GLOBAL.gtid_executed;en cada uno) y después arrancar Group Replication en los demás.
Paso 8: Probar el failover automático
Para MySQL en el primario (mysql1):
sudo systemctl stop mysql
Desde mysql2, comprueba el grupo. En pocos segundos uno de los secundarios pasa a primario:
sudo mysql -e "SELECT MEMBER_HOST, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members;"
+-------------+--------------+-------------+
| MEMBER_HOST | MEMBER_STATE | MEMBER_ROLE |
+-------------+--------------+-------------+
| 10.0.0.12 | ONLINE | PRIMARY |
| 10.0.0.13 | ONLINE | SECONDARY |
+-------------+--------------+-------------+
El nuevo primario desactiva super_read_only y acepta escrituras. Vuelve a arrancar MySQL en mysql1:
sudo systemctl start mysql
Con group_replication_start_on_boot = ON, se une de nuevo como SECONDARY y recupera las transacciones que se perdió.
Paso 9: Cambiar el primario y gestionar miembros
Para devolver el rol de primario a mysql1 (por ejemplo, porque tiene más recursos), obtén su UUID de miembro:
sudo mysql -e "SELECT MEMBER_ID, MEMBER_HOST, MEMBER_ROLE FROM performance_schema.replication_group_members;"
Y ejecuta desde cualquier miembro, con el MEMBER_ID de mysql1:
sudo mysql -e "SELECT group_replication_set_as_primary('member_id_de_mysql1');"
Para retirar un miembro de forma ordenada (por ejemplo, antes de actualizarlo), ejecuta en ese nodo:
sudo mysql -e "STOP GROUP_REPLICATION;"
El resto del grupo sigue funcionando. Cuando termines, vuelve a unirlo con START GROUP_REPLICATION;. Para añadir un cuarto nodo, repite los pasos 1 a 3 en él con un server_id nuevo, añade su dirección a group_replication_group_seeds en todos los nodos y ejecuta START GROUP_REPLICATION;.
Notael modo multiprimario, en el que todos los miembros aceptan escrituras, se activa con
SELECT group_replication_switch_to_multi_primary_mode();. Implica conflictos de certificación cuando dos miembros modifican la misma fila y restricciones adicionales (por ejemplo, con claves foráneas en cascada), así que el modo primario único es la opción recomendada para la mayoría de aplicaciones.
Paso 10: Monitorizar el grupo
Además del estado de los miembros, performance_schema.replication_group_member_stats muestra si algún nodo acumula transacciones pendientes de aplicar o de certificar:
sudo mysql -e "SELECT MEMBER_ID, COUNT_TRANSACTIONS_IN_QUEUE, COUNT_TRANSACTIONS_REMOTE_IN_APPLIER_QUEUE, COUNT_CONFLICTS_DETECTED FROM performance_schema.replication_group_member_stats\G"
Valores de cola que crecen de forma sostenida indican que un miembro va más lento que el resto. Si se retrasa demasiado, el control de flujo del grupo frena las escrituras en el primario para que pueda alcanzarlo.
Solución de problemas
This member has more executed transactions than those present in the group: el nodo tiene transacciones locales que el grupo no conoce, normalmente por crear usuarios o bases de datos sin SET SQL_LOG_BIN = 0. En un nodo recién instalado y sin datos propios, puedes limpiar su historial GTID con RESET MASTER; y volver a ejecutar START GROUP_REPLICATION;. No lo hagas en un nodo con datos que no existan en el grupo.
El nodo se queda en RECOVERING o pasa a ERROR: revisa el log de errores con sudo tail -n 50 /var/log/mysql/error.log. Las causas habituales son credenciales incorrectas en el canal group_replication_recovery, el puerto 3306 cerrado entre nodos o un report_host al que los demás no llegan.
START GROUP_REPLICATION falla con errores de conexión al puerto 33061: comprueba el firewall y que group_replication_local_address usa la IP de ese nodo. Por defecto, MySQL solo acepta miembros desde redes privadas (group_replication_ip_allowlist = AUTOMATIC); si tus nodos usan IP públicas, define esa variable con las direcciones de los miembros.
Error al crear tablas sin clave primaria: Group Replication rechaza las tablas InnoDB sin clave primaria o única no nula. Añade una clave primaria a la tabla.
Conclusión
Tienes un grupo MySQL de tres nodos en Ubuntu 24.04 en modo primario único, con tráfico cifrado entre miembros, failover automático y los procedimientos para cambiar el primario y retirar o añadir nodos. Como siguientes pasos puedes:
- Instalar MySQL Router delante del grupo para que las aplicaciones se conecten siempre al primario actual sin cambiar su configuración.
- Programar copias de seguridad desde un secundario con
mysqldump --single-transactiono Percona XtraBackup. - Añadir alertas sobre los miembros que no estén
ONLINEy sobre el crecimiento de las colas de transacciones.
