Javier Valencia Javier Valencia
MariaDB desde cero (V): replicación, Galera y producción

MariaDB desde cero (V): replicación, Galera y producción

Javier Valencia · · 6 min de lectura · 28 visitas · Desarrollo
bases-de-datos tutorial mariadb mysql devops mariadb-desde-cero

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_Running y Slave_SQL_Running: deben ser Yes.
  • Seconds_Behind_Master: lag aproximado.
  • Gtid_IO_Pos: posición actual en términos de GTID.
  • Last_Error y Last_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:

  1. 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
    
  2. scram-sha-256 / ed25519 para autenticación moderna (en vez de mysql_native_password):
    CREATE USER 'app'@'10.%.%.%'
      IDENTIFIED VIA ed25519 USING PASSWORD('xxx');
    
  3. Usuarios con permisos mínimos. La app nunca como root.
  4. Red privada: MariaDB nunca expuesto a internet.
  5. Audit log con el plugin server_audit:
    plugin_load_add = server_audit
    server_audit_logging = ON
    server_audit_events = CONNECT,QUERY_DDL,QUERY_DCL
    
  6. Validación de contraseñas con simple_password_check.
  7. Actualizaciones regulares de minor.
  8. Roles (ver entrega I) para separar permisos.

Upgrades

  • Minor (11.4.x → 11.4.y): simple. Parar, actualizar paquete, arrancar, mariadb-upgrade por 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.

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_size ajustado 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:

Y ampliando horizonte de bases de datos:

Si tienes dudas sobre montar Galera, elegir entre async y Galera, o depurar un bloqueo recurrente, mis DMs siguen abiertos.