MariaDB desde cero (V): replicación, Galera y producción
Quinta y última entrega de la serie MariaDB desde cero a pro. Tiempo de lectura estimado: 14 minutos.
Último tramo. Has aprendido a instalar MariaDB (I), diseñar esquemas con storage engines y tipos adecuados (II), escribir consultas modernas (III) y diagnosticar rendimiento (IV). Ahora toca lo que define "estar en producción": replicación, Galera, backups, monitorización y seguridad.
Comparativa honesta: ponerlo todo a funcionar en MariaDB es más artesanal que en un PostgreSQL con Patroni o un RDS gestionado. No es más difícil; es distinto. Te paga en flexibilidad.
Binlog: la base de todo
MariaDB mantiene un binary log (binlog): un log secuencial de cambios que sirve para replicación y point-in-time recovery. Activarlo es requisito para todo lo serio.
[mariadb]
server_id = 1
log_bin = /var/log/mysql/mariadb-bin
binlog_format = ROW # ROW es el estándar moderno
binlog_row_image = MINIMAL # menos espacio en replicación
expire_logs_days = 7
sync_binlog = 1 # durable, a costa de algo de rendimiento
Formatos de binlog:
- STATEMENT: guarda el SQL. Compacto, pero problemático con funciones no deterministas.
- ROW: guarda los cambios fila a fila. Grande, pero completamente determinista. Usa este.
- MIXED: mezcla. Evitable.
Replicación asíncrona
La replicación "clásica": una primaria y una o varias réplicas que aplican los cambios después. Desde hace años, lo estándar es usar GTID (Global Transaction ID), que identifica cada transacción globalmente y hace trivial el failover y el reposicionamiento.
Config en la primaria
[mariadb]
server_id = 1
log_bin = /var/log/mysql/mariadb-bin
binlog_format = ROW
gtid_domain_id = 1
gtid_strict_mode = ON
log_slave_updates = ON
Crear el usuario para las réplicas:
CREATE USER 'repl'@'10.0.%.%' IDENTIFIED BY 'xxx';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl'@'10.0.%.%';
Config en la réplica
[mariadb]
server_id = 2
log_bin = /var/log/mysql/mariadb-bin # también en réplicas
binlog_format = ROW
gtid_domain_id = 1
gtid_strict_mode = ON
log_slave_updates = ON
read_only = ON
Y desde SQL:
CHANGE MASTER TO
MASTER_HOST='primary.internal',
MASTER_USER='repl',
MASTER_PASSWORD='xxx',
MASTER_USE_GTID=current_pos;
START SLAVE;
SHOW SLAVE STATUS\G
Las líneas clave en SHOW SLAVE STATUS:
Slave_IO_RunningySlave_SQL_Running: deben serYes.Seconds_Behind_Master: lag aproximado.Gtid_IO_Pos: posición actual en términos de GTID.Last_ErroryLast_SQL_Error: si algo ha roto.
Replicación paralela
Desde MariaDB 10, la réplica puede aplicar cambios en paralelo. En postgresql.conf de la réplica:
slave_parallel_mode = optimistic
slave_parallel_threads = 8
slave_parallel_workers = 8
Esto ayuda enormemente cuando la réplica iba quedándose atrás con cargas de escritura fuertes.
Semi-sync
Asíncrona pura tiene un riesgo claro: si la primaria cae antes de que el binlog llegue a las réplicas, los commits recientes se pierden. Semi-sync mitiga: la primaria espera al ACK de al menos una réplica antes de confirmar al cliente.
# En primaria
rpl_semi_sync_master_enabled = ON
rpl_semi_sync_master_timeout = 10000 # 10s antes de caer a async
# En réplicas
rpl_semi_sync_slave_enabled = ON
No es garantía total, pero reduce muchísimo la ventana de pérdida.
Galera Cluster: replicación síncrona multi-master
Galera es una tecnología de replicación síncrona integrada en MariaDB (paquete mariadb-server incluye el wsrep provider de serie). Características:
- Multi-master: todos los nodos aceptan escrituras.
- Síncrona: un commit no se confirma hasta que todos los nodos lo han aceptado.
- Consistencia: no hay lag de replicación (sí algo de latencia de commit).
- Tolerancia: con quórum (N/2 + 1), el cluster sigue funcionando.
Ideal para:
- Aplicaciones que exigen HA síncrona entre dos o tres data centers cercanos.
- Escenarios donde el downtime es inaceptable y toleras algo de latencia añadida en escritura.
Config mínima
En /etc/mysql/mariadb.conf.d/60-galera.cnf:
[galera]
wsrep_on = ON
wsrep_provider = /usr/lib/galera/libgalera_smm.so
wsrep_cluster_name = "blog_cluster"
wsrep_cluster_address = "gcomm://10.0.0.1,10.0.0.2,10.0.0.3"
wsrep_node_address = "10.0.0.1"
wsrep_node_name = "ch-01"
wsrep_sst_method = mariabackup
wsrep_sst_auth = "sst:xxx"
binlog_format = ROW
default_storage_engine = InnoDB
innodb_autoinc_lock_mode = 2
bind_address = 0.0.0.0
Bootstrap del primer nodo (solo la primera vez):
galera_new_cluster
Y en el resto de nodos, arranque normal:
systemctl start mariadb
Verificar estado del cluster:
SHOW STATUS LIKE 'wsrep_cluster_size';
SHOW STATUS LIKE 'wsrep_cluster_status';
SHOW STATUS LIKE 'wsrep_ready';
SHOW STATUS LIKE 'wsrep_local_state_comment';
Señales de salud:
wsrep_cluster_size= número de nodos esperado.wsrep_cluster_status=Primary.wsrep_ready=ON.wsrep_local_state_comment=Synced.
Consideraciones de Galera
- Latencia de red entre nodos: Galera hace un consensus por transacción. Si los nodos están en DCs distantes, cada commit paga ese RTT.
- Write conflicts: si dos nodos modifican la misma fila a la vez, uno recibe error 1213 (deadlock). La app debe reintentar.
- Tablas sin PK: no se replican bien. Todas las tablas necesitan PK. InnoDB ya lo recomienda igualmente.
- DDL: Galera soporta dos métodos de aplicación, Total Order Isolation (TOI, bloquea el cluster) y Rolling Schema Upgrade (RSU, nodo por nodo). TOI es el default y más seguro.
- Escalado de escritura: Galera NO escala escrituras (todas las escrituras tienen que aplicarse en todos los nodos). Lo que te da es HA y lecturas distribuidas.
Para escalar escrituras necesitas sharding, que en MariaDB se hace o con Spider o con lógica de aplicación.
Backups
mariabackup
La herramienta moderna, derivada de Percona XtraBackup. Backup físico en caliente, sin bloquear escrituras. Soporta Galera.
Instalación:
sudo apt install -y mariadb-backup
Backup:
mariabackup --backup --target-dir=/backups/$(date +%Y%m%d-%H%M) \
--user=bkp --password=xxx
Backup incremental (requiere un full previo):
mariabackup --backup \
--target-dir=/backups/inc-$(date +%Y%m%d-%H%M) \
--incremental-basedir=/backups/full-20260518 \
--user=bkp --password=xxx
Restore:
# Preparar (aplica log)
mariabackup --prepare --target-dir=/backups/full-20260518
# Copiar al datadir (con el servicio parado y datadir vacío)
systemctl stop mariadb
rm -rf /var/lib/mysql/*
mariabackup --copy-back --target-dir=/backups/full-20260518
chown -R mysql:mysql /var/lib/mysql
systemctl start mariadb
Para restore a un instante concreto, aplicas los binlogs con mysqlbinlog:
mysqlbinlog --start-position=... --stop-datetime='2026-05-18 12:34:56' \
/var/log/mysql/mariadb-bin.00* | mariadb
mysqldump (lógico)
Para migraciones y respaldos pequeños:
mariadb-dump --single-transaction --routines --triggers --events \
--databases blog > blog.sql
--single-transaction hace el dump dentro de una transacción REPEATABLE READ, evitando bloqueos. Para tablas no-InnoDB (MyISAM, Aria), esto no sirve y hay que usar --lock-tables.
Estrategia de backup sensata
- Full diario (mariabackup).
- Incremental cada hora o cada 6 h.
- Binlog copiado a almacenamiento externo en tiempo real (puedes hacer
mysqlbinlog --read-from-remote-server --raw ...en un script con systemd timer). - Retención: 7–30 días según compliance.
- Almacenamiento: S3, GCS o equivalente. Nunca en la misma máquina.
- Restore probado mensualmente. Un backup no probado es una suposición.
Monitorización
Métricas imprescindibles:
- QPS / TPS.
- Tasa de errores SQL (1213 deadlocks, 1205 lock wait timeouts).
- Buffer pool hit ratio: objetivo > 99%.
- Replication lag (
Seconds_Behind_Master). - Threads_connected vs
max_connections. - Disk I/O y espacio en datadir y en
pg_wal-equivalente (/var/log/mysql). - Galera:
wsrep_cluster_size,wsrep_flow_control_paused,wsrep_local_recv_queue_avg.
Herramientas:
- Prometheus + mysqld_exporter + Grafana. Dashboards listos en grafana.com. Mismo stack que el post Prometheus y Grafana para servicios pequeños.
- Percona PMM: plataforma completa de monitorización, open source, muy visual. Mi elección si quieres lo mejor listo de serie.
- pt-stalk / pt-summary (Percona Toolkit): diagnóstico puntual.
Alertas mínimas
- Replication lag > 30 s.
- Cluster size distinto al esperado (Galera).
- Deadlocks nuevos > 0 en 5 min (según tu tolerancia).
- Disco > 80%.
- Conexiones usadas > 80% del máximo.
- Buffer pool hit ratio < 99% durante 10 min.
- Slow queries nuevas en el top.
Seguridad en producción
Mínimo aceptable:
- TLS obligatorio en conexiones externas:
[mariadb] ssl_cert = /etc/mysql/server-cert.pem ssl_key = /etc/mysql/server-key.pem ssl_ca = /etc/mysql/ca.pem require_secure_transport = ON - scram-sha-256 / ed25519 para autenticación moderna (en vez de
mysql_native_password):CREATE USER 'app'@'10.%.%.%' IDENTIFIED VIA ed25519 USING PASSWORD('xxx'); - Usuarios con permisos mínimos. La app nunca como
root. - Red privada: MariaDB nunca expuesto a internet.
- Audit log con el plugin
server_audit:plugin_load_add = server_audit server_audit_logging = ON server_audit_events = CONNECT,QUERY_DDL,QUERY_DCL - Validación de contraseñas con
simple_password_check. - Actualizaciones regulares de minor.
- Roles (ver entrega I) para separar permisos.
Upgrades
- Minor (11.4.x → 11.4.y): simple. Parar, actualizar paquete, arrancar,
mariadb-upgradepor si hay ajustes de metadata. - Major (10.11 → 11.4): varias rutas:
- In-place: parar, reinstalar paquete de la versión nueva, arrancar,
mariadb-upgrade. - Réplica nueva: levantar una réplica en la versión nueva, promocionar, retirar la antigua.
- mysqldump: migración lógica, lenta pero segura.
- In-place: parar, reinstalar paquete de la versión nueva, arrancar,
En cluster Galera, los upgrades se hacen nodo a nodo, en rolling. Siempre que la versión nueva sea compatible con la del cluster durante el proceso (consulta la guía oficial para cada salto).
Checklist de producción
- Backups full + incremental automatizados a almacenamiento externo.
- Restore probado en entorno limpio.
- Replicación configurada con GTID; al menos una réplica.
- Semi-sync o Galera activo si el nivel de durabilidad lo exige.
- Failover documentado y probado.
- Connection pooler (ProxySQL / MaxScale / equivalentes).
- Monitorización con las métricas de arriba + alertas.
- TLS y autenticación robusta.
-
innodb_buffer_pool_sizeajustado a la RAM real (ver entrega IV). - Slow query log activado y revisado periódicamente.
- Logs centralizados.
- Binlog con expiración razonable y copiado fuera.
- Plan de upgrades con ventanas definidas.
- Red privada, sin MariaDB expuesto a internet.
Cierre de la serie
Fin del recorrido. En cinco posts hemos pasado de no haber tocado MariaDB a tenerlo desplegado en producción con replicación y backups serios.
Una observación sobre el ecosistema: MariaDB tiene una filosofía muy pragmática. Integra lo que funciona (Galera, mariabackup, ColumnStore) en el producto base y mantiene una compatibilidad alta con MySQL para que no te quedes atrás. A cambio, te pide más trabajo manual que un PostgreSQL con Patroni o que un servicio gestionado. Es un trade-off razonable si tu equipo valora el control.
Serie completa:
- I: instalación y primeros pasos
- II: storage engines, tipos y restricciones
- III: consultas, CTEs y window functions
- IV: índices, EXPLAIN y tuning
- V: replicación, Galera y producción (estás aquí)
Y ampliando horizonte de bases de datos:
- PostgreSQL desde cero a pro: la opción por defecto para la mayoría de aplicaciones.
- ClickHouse desde cero a pro: cuando lo tuyo es analítica a escala.
- MySQL y MariaDB, MariaDB y MySQL: la comparativa honesta entre los dos forks.
Si tienes dudas sobre montar Galera, elegir entre async y Galera, o depurar un bloqueo recurrente, mis DMs siguen abiertos.