En diagramas, la replicación parece una línea recta: el primario escribe, las réplicas siguen y todos se van a casa.
En producción es una escena del crimen: una réplica que “funciona” pero está equivocada, un failover que “salvó” la situación pero perdió datos,
o un gráfico de latencia que se aplana justo cuando el CEO está mostrando la demo.
MariaDB y Percona Server ambos hablan “estilo MySQL”, pero sus casos límite en replicación no coinciden exactamente.
Las peores fallas vienen de asumir que sí. Esta es una guía de campo para las esquinas afiladas: GTID, binlogs,
seguridad ante crashes, filtros, semi-sync y las prácticas operativas que te mantienen fuera del infierno de revisiones de incidentes.
Qué estás eligiendo realmente (pista: semántica operacional)
“MariaDB vs Percona Server” suena a una lista de características. La replicación lo convierte en una elección de comportamiento.
En tiempos normales, ambos transmitirán eventos de binlog a las réplicas y los aplicarán. Bajo estrés —particiones de red,
bloqueos de disco, failovers, recuperación tras crash— las diferencias aparecen como: qué se escribe en el binlog, qué se
reconoce, qué se considera seguro y qué asume tu herramienta.
Percona Server es una variante de MySQL que normalmente sigue de cerca el comportamiento de Oracle MySQL mientras añade instrumentación,
ajustes y parches operativos (a menudo orientados a rendimiento u observabilidad). MariaDB es un fork propio con
características de replicación que a veces van por delante, a veces son simplemente distintas y ocasionalmente incompatibles de forma sutil—
especialmente en torno a la semántica de GTID.
Aquí va el encuadre opinado que se mantiene en los outages:
- Si necesitas “compatibilidad con el ecosistema MySQL primero”, Percona Server suele ser la apuesta más segura. Muchas herramientas esperan detalles de GTID y binlog al estilo Oracle.
- Si quieres funciones específicas de MariaDB (y aceptas sus semánticas), comprométete por completo: usa GTID de MariaDB de extremo a extremo, herramientas compatibles con MariaDB y prueba las rutas de failover como pruebas de respaldo: rutinariamente.
- Si planeas mezclar MariaDB y Percona en la misma topología de replicación, hazlo solo con una matriz de compatibilidad por escrito y un laboratorio que reproduzca tus binlogs reales. “Funcionó una vez” no es una matriz.
Hechos históricos que explican la rareza actual
Son fragmentos breves y concretos de historia que importan porque la “rareza” en replicación suele ser “decisiones heredadas tomadas en público”.
Tenlos en mente cuando depures.
- La replicación de MySQL comenzó como replicación basada en sentencias (SBR), que era frágil con SQL no determinista; la replicación basada en filas (RBR) llegó después y cambió las expectativas operativas.
- MariaDB se bifurcó de MySQL en 2009 y evolucionó sus funciones de replicación de forma independiente, incluyendo su propia implementación de GTID y metadatos.
- GTID de Oracle MySQL (5.6+) y GTID de MariaDB no son el mismo protocolo; resuelven problemas similares con identificadores y reglas de failover distintas.
- Percona Server históricamente incorporó parches “amigables para operadores” como mejor instrumentación y controles de rendimiento; esto influyó en cómo los equipos monitorizan replicación (y qué esperan ver).
- MySQL 5.7/8.0 convirtió RBR en la opción por defecto en muchas empresas porque redujo la “deriva” de réplicas, pero aumentó el volumen de binlog y la sensibilidad al IO.
- La replicación multihilo llegó por etapas: primero paralelismo grueso, luego apply paralelo más granular basado en “reloj lógico”/GTID; MariaDB tiene su propio enfoque y ajustes de replicación paralela.
- Semi-synchronous replication se añadió como plugin y evolucionó con el tiempo; reduce pero no elimina los riesgos de pérdida de datos en ciertas secuencias de failover.
- La seguridad ante crashes en replicación mejoró con los años mediante repositorios de metadatos y recuperación de relay log, pero las opciones de configuración aún pueden devolverte a 2012.
- Los checksums y metadatos de eventos del binlog crecieron con el tiempo; la replicación entre versiones y sabores puede romperse por nimiedades como “el binlog dice CRC32 y la réplica no está de acuerdo”.
Modelos de replicación y dónde divergen MariaDB y Percona
Replicación asíncrona: la predeterminada que miente con cortesía
La replicación asíncrona clásica significa que el primario confirma el commit y le dice al cliente “OK” sin esperar a las réplicas.
Es rápida. También es honesta en una cosa: si el primario muere, podrías perder las últimas transacciones.
Los casos límite aparecen cuando la gente olvida que el ACK al cliente no es una garantía de durabilidad más allá de la configuración de almacenamiento del primario.
La diferencia MariaDB vs Percona aquí no es filosófica. Está en los detalles:
cómo se rastrea el estado de GTID, cómo la recuperación ante crash reposiciona los relay logs, qué valores por defecto se envían y qué asume tu
herramienta de orquestación.
Fila vs sentencia vs mixto: el formato de replicación no es una preferencia
Si aún ejecutas replicación basada en sentencias en sistemas críticos, básicamente estás apostando tu trabajo a que cada consulta sea determinista bajo todos los planes de ejecución, zonas horarias, modos SQL y semánticas de funciones.
Es una elección de vida atrevida.
RBR es más seguro para la corrección pero más pesado en disco, IO y a veces en red. Mixed intenta ser listo y a menudo te sorprende a las 3 a.m. El caso límite importante es: una única sentencia no determinista puede causar deriva de réplicas,
y entonces cada failover “exitoso” es solo cambiar a una base de datos equivocada más rápido.
Percona Server vs MariaDB: lo que sienten los operadores
A los operadores no les importan los eslóganes; les importa si las herramientas de failover toman decisiones correctas.
En Percona Server (alineado con las semánticas de Oracle MySQL), GTID e internals de replicación tienden a comportarse como el ecosistema MySQL en general espera. Las funciones de replicación de MariaDB pueden ser excelentes, pero no siempre son compatibles de forma transparente.
Traducción: puedes ejecutar cualquiera bien, pero no improvises. La replicación castiga la improvisación.
GTID: el mayor arma de doble filo con mejor marketing
Los GTID deberían hacer que el failover fuera aburrido: cada transacción tiene un ID global, las réplicas saben qué han ejecutado
y puedes promover una réplica sin contar posiciones de binlog a mano.
Los casos límite vienen de dos hechos:
- GTID de MariaDB y GTID de Oracle/MySQL son sistemas diferentes con formatos y manejo de estado distintos.
- La corrección de GTID depende de cómo configures el logging, la seguridad ante crashes y las suposiciones de tu herramienta de failover.
GTID de MariaDB vs GTID de MySQL/Percona: “mismo acrónimo, contrato distinto”
En el estilo MySQL/Percona de GTID, el UUID del servidor (o el conjunto de identificadores del servidor) está integrado en conjuntos GTID y variables de estado como gtid_executed. MariaDB usa un GTID basado en dominios con variables y convenciones distintas.
Ambos pueden soportar comportamiento de “auto-positioning”, pero el nivel de wire y los metadatos no son intercambiables.
Mezclar sabores a través de límites de GTID es donde los equipos sangran. Si replicás de MariaDB a Percona o viceversa,
debés validar:
- Si GTID está soportado en esa dirección y combinación de versiones.
- Si tu canal de replicación entiende el formato GTID emitido por el primario.
- Si tu herramienta de failover lee las variables de estado correctas y las interpreta adecuadamente.
Failover con GTID: qué significa realmente “seguro”
Un failover “seguro” con GTID requiere dos condiciones:
- El candidato a replica ha recibido todas las transacciones que fueron reconocidas a los clientes (o tu app acepta perder algunas).
- El candidato ha aplicado esas transacciones y no las volverá a aplicar ni las saltará tras la promoción.
GTID ayuda con la condición #2 (no re-aplicar transacciones) si se configura correctamente. No garantiza la #1. Ahí
es donde semi-sync, las configuraciones de durabilidad (sync_binlog, innodb_flush_log_at_trx_commit) y el timing de red importan.
Chiste #1
GTID es como etiquetar las sobras: aún tienes que meterlas en la nevera si no quieres arrepentirte después.
Compatibilidad de binlog: checksums, formatos y desajustes silenciosos
La replicación es, en última instancia, un contrato: “Yo escribiré eventos así; tú los entenderás y aplicarás.”
Los contratos se rompen de tres maneras: el primario cambia lo que escribe, la réplica cambia lo que entiende,
o un intermediario edita el tráfico silenciosamente (raro, pero he visto proxies “útiles” hacer tonterías).
Checksums del binlog: ajuste pequeño, gran outage
Los checksums del binlog protegen contra corrupción, pero la compatibilidad depende de que ambos extremos estén de acuerdo.
Un modo clásico de falla es actualizar un lado o cambiar un valor por defecto y ver cómo la replicación se detiene con un error de parseo.
Consejo práctico: estandariza la configuración de checksum del binlog en toda la flota y hazla parte de tus auditorías base.
No dejes que un servidor sea “especial”.
Formato del binlog: RBR es más seguro, pero cuidado con la latencia por volumen
Al pasar a RBR, a menudo arreglas problemas de corrección mientras creas nuevos cuellos de botella de rendimiento:
las réplicas se vuelven limitadas por IO al aplicar imágenes de filas grandes y los relay logs se inflan.
Percona Server y MariaDB manejan RBR, pero su apply paralelo y los ajustes difieren. El caso límite no es “si puede replicar”
sino “si puede mantenerse al día durante ráfagas de escritura y cambios de esquema.”
Tipos de eventos y desfase de versiones
La replicación entre versiones (incluso del mismo sabor) es donde aparecen tipos de evento raros.
Un primario más nuevo puede emitir eventos que una réplica algo más antigua no puede parsear. A veces obtienes un error limpio. A veces
parece lag, luego una parada, luego un operador confundido que vuelve a ejecutar START SLAVE como estrategia de afrontamiento.
Semi-sync y escenarios de “pérdida de datos igual”
La replicación semi-síncrona reduce la ventana de pérdida al esperar que al menos una réplica acuse recibo
del evento antes de que el primario devuelva OK. Acuse de recibo, no aplicación. Si la réplica reconocida tiene el evento en
un relay log pero no lo ha comprometido, un failover aún puede perderlo—o peor, bifurcar el historial dependiendo de tu procedimiento.
Aquí es donde muchos ejecutivos oyen “semi-sync” y piensan “sin pérdida de datos”. Esa creencia ha provocado más de una reunión incómoda con Finanzas.
Lo que realmente compra semi-sync
- Menos transacciones reconocidas que existen solo en el primario.
- Mejores probabilidades de que una réplica promovida contenga las últimas escrituras confirmadas.
- Más latencia y más sensibilidad a jitter de réplica/red.
Secuencia de fallo que aún pierde datos
El primario confirma, envía a la réplica, la réplica ACKea recibo, el primario ACKea al cliente. Luego la réplica se cae antes de aplicar,
o el relay log se corrompe, o el failover promociona otra réplica que nunca lo recibió. Enhorabuena:
semi-sync, resultados asíncronos.
Postura del operador
Usa semi-sync si tu presupuesto de latencia lo permite y entiendes sus garantías. Emparejalo con reglas de promoción:
solo promover réplicas que se confirmen al día y lo suficientemente durables para tu RPO.
De otro modo, solo estarás pagando latencia por una sensación de seguridad.
Replicación paralela: más rápido hasta que deja de serlo
La replicación paralela es una función de rendimiento que se convierte en debate de corrección en cuanto tengas transacciones cross-schema,
filas calientes o una carga que es “mayormente paralela excepto por las partes que importan”.
El caso límite: “optimizas el lag” aumentando threads workers, pero la réplica se vuelve limitada por CPU, por mutex,
o comienza a thrashear el buffer pool y el apply se ralentiza. O se mantiene al día—hasta que llega un DDL y todo se amontona
detrás como coches detrás de un desfile.
Percona Server (alineado con MySQL) típicamente usa mecánicas de apply paralelo al estilo MySQL e instrumentación que muchas herramientas esperan.
MariaDB tiene su propio sistema de replicación paralela y variables, y los patrones de afinamiento no siempre son transferibles. Debes medir, no adivinar.
Filtros y cambios de esquema: desastres de combustión lenta
Los filtros de replicación (replicate-do-db, replicate-ignore-db, comodines, filtros de tabla)
parecen una forma ordenada de “mantener solo lo que necesitas”. En realidad son una obligación a largo plazo a menos que los trates
como código: revisados, probados y revalidados después de cada cambio de esquema.
Filtros + formato binlog mixto + consultas cross-db pueden hacer que las réplicas pierdan cambios en silencio.
Silencioso es la peor palabra en replicación.
Replicación de DDL: donde “funcionó en staging” va a morir
El DDL es brutal para las réplicas. A menudo es single-threaded, bloquea y puede crear eventos de cambios de filas enormes.
Las herramientas de cambio de esquema online reducen el impacto pero introducen sus propios casos límite: triggers, tablas fantasma y picos de lag.
Si tienes que elegir una filosofía: prioriza la corrección y la recuperación predecible sobre el rendimiento pico.
Puedes comprar hardware para rendimiento. No puedes comprar una salida para datos inconsistentes tras un mal failover.
Tareas prácticas: comandos, salidas y las decisiones que tomas
A continuación hay tareas operativas reales. Cada una incluye un comando, salida de ejemplo, qué significa y qué decisión tomar.
Úsalas como memoria muscular durante incidentes y en auditorías aburridas de los martes. El martes aburrido es donde ganas.
Tarea 1: Identificar el sabor y la versión del servidor (deja de adivinar)
cr0x@server:~$ mysql -e "SELECT @@version, @@version_comment\G"
*************************** 1. row ***************************
@@version: 10.11.6-MariaDB-1:10.11.6+maria~ubu2204
@@version_comment: MariaDB Server
Qué significa: Estás en MariaDB 10.11.x. Si tu runbook asume variables GTID de MySQL/Percona, ya está equivocado.
Decisión: Usa la sintaxis/variables de replicación de MariaDB y asegúrate de que tu herramienta de failover soporte GTIDs de MariaDB (si están activados).
Tarea 2: Comprobar el binlog del primario y la postura de durabilidad
cr0x@server:~$ mysql -e "SHOW VARIABLES WHERE Variable_name IN ('log_bin','binlog_format','sync_binlog','innodb_flush_log_at_trx_commit')"
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| binlog_format | ROW |
| innodb_flush_log_at_trx_commit | 1 |
| log_bin | ON |
| sync_binlog | 1 |
+--------------------------------+-------+
Qué significa: Los binlogs están habilitados, se usa replicación basada en filas y la durabilidad es estricta (mayor coste IO, mejor seguridad ante crashes).
Decisión: Si la latencia es aceptable, mantenlo. Si te tienta relajarlo, hazlo solo con una aprobación explícita de RPO/RTO y un plan de recuperación probado.
Tarea 3: Confirmar el estado de la réplica (la línea base aburrida)
cr0x@server:~$ mysql -e "SHOW SLAVE STATUS\G" | egrep "Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master|Last_SQL_Error|Last_IO_Error"
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 0
Last_IO_Error:
Last_SQL_Error:
Qué significa: Los threads están en ejecución y la réplica declara no tener lag. Esto es necesario, no suficiente, para la corrección.
Decisión: Si estás diagnosticando “resultados incorrectos”, debes ir más allá y verificar GTIDs/posiciones/checksums ejecutados.
Tarea 4: Medir correctamente la latencia de replicación (no adores Seconds_Behind_Master)
cr0x@server:~$ pt-heartbeat --check --database=percona --table=heartbeat --host=127.0.0.1 --user=monitor --password='***'
0.183
Qué significa: La latencia observada real es ~183ms. Esto suele ser más fiable que Seconds_Behind_Master bajo carga o apply paralelo.
Decisión: Usa lag basado en heartbeat para alertas y gating de failover. Trata Seconds_Behind_Master como una pista, no como un oráculo de verdad.
Tarea 5: Validar compatibilidad de checksum del binlog
cr0x@server:~$ mysql -e "SHOW VARIABLES LIKE 'binlog_checksum';"
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| binlog_checksum | CRC32 |
+-----------------+-------+
Qué significa: El primario emite checksums CRC32. Una réplica que espere NONE (o que no soporte) puede fallar al leer eventos.
Decisión: Asegura que las réplicas estén configuradas para entender el mismo modo de checksum; estandarízalo en la flota antes de upgrades.
Tarea 6: Detectar presión en relay logs y riesgo de disco
cr0x@server:~$ du -sh /var/lib/mysql/*relay* 2>/dev/null | tail -n 3
18G /var/lib/mysql/relay-bin.000112
18G /var/lib/mysql/relay-bin.000113
36G /var/lib/mysql/relay-log.info
Qué significa: Los relay logs son enormes. Esto suele correlacionar con lag o apply lento del hilo SQL.
Decisión: Antes de reiniciar nada, encuentra el cuello de botella de apply (IO, locks, DDL). Si el disco está casi lleno, prioriza detener la hemorragia: limita escrituras, añade espacio o provisiona una nueva réplica.
Tarea 7: Encontrar las coordenadas actuales de replicación (la posición de binlog aún importa)
cr0x@server:~$ mysql -e "SHOW MASTER STATUS\G"
*************************** 1. row ***************************
File: mysql-bin.001874
Position: 918273645
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set:
Qué significa: Tienes un archivo/posición de binlog. Incluso con GTID, esto es útil para comparaciones puntuales y depuración.
Decisión: Registra esto antes de operaciones riesgosas (failover, restart, cambio de configuración). Es tu rastro de migas cuando estás cansado.
Tarea 8: Comprobar si la réplica aplica en paralelo (y si ayuda)
cr0x@server:~$ mysql -e "SHOW VARIABLES LIKE 'slave_parallel_workers';"
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| slave_parallel_workers | 16 |
+------------------------+-------+
Qué significa: La réplica está configurada con 16 workers paralelos (nombre de variable estilo MySQL/Percona; MariaDB usa otros knobs según versión).
Decisión: Si el lag empeora tras aumentar workers, reduce y perfila: saturación CPU, esperas por mutex, stalls de IO y serialización por DDL son culpables comunes.
Tarea 9: Inspeccionar estados de workers de replicación para identificar el bloqueo
cr0x@server:~$ mysql -e "SELECT THREAD_ID,PROCESSLIST_STATE,PROCESSLIST_INFO FROM performance_schema.threads t JOIN performance_schema.processlist p ON t.PROCESSLIST_ID=p.ID WHERE p.COMMAND IN ('Connect','Binlog Dump GTID','Binlog Dump','Query') LIMIT 5\G"
*************************** 1. row ***************************
THREAD_ID: 82
PROCESSLIST_STATE: Waiting for master to send event
PROCESSLIST_INFO: NULL
*************************** 2. row ***************************
THREAD_ID: 109
PROCESSLIST_STATE: Waiting for handler commit
PROCESSLIST_INFO: INSERT INTO orders ...
Qué significa: El hilo IO está inactivo (bien), pero un worker está bloqueado esperando commit—a menudo IO, fsync o contención.
Decisión: Mira la latencia de disco y la presión de flush de InnoDB. No solo subas workers; multiplicarás la contención.
Tarea 10: Comprobar latencia de disco (el lag a menudo es latencia de almacenamiento)
cr0x@server:~$ iostat -x 1 3
Device r/s w/s r_await w_await aqu-sz %util
nvme0n1 120.0 980.0 1.10 18.70 7.42 92.0
Qué significa: Las escrituras esperan ~19ms de media y el dispositivo está ~92% utilizado. Probablemente el hilo SQL de la réplica esté limitado por IO.
Decisión: Reduce la amplificación de escritura (tuning del buffer pool, dimensionado de log files), mueve réplicas a almacenamiento más rápido o reduce temporalmente la tasa de escrituras entrantes. Ajustar CPU no arreglará un disco saturado.
Tarea 11: Confirmar ajustes de recuperación crash-safe de relay log
cr0x@server:~$ mysql -e "SHOW VARIABLES WHERE Variable_name IN ('relay_log_recovery','master_info_repository','relay_log_info_repository');"
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| master_info_repository | TABLE |
| relay_log_info_repository | TABLE |
| relay_log_recovery | ON |
+-------------------------+-------+
Qué significa: Los metadatos se almacenan en tablas y la recuperación de relay log está activada—bueno para seguridad ante crashes.
Decisión: Si en la flota esto está en FILE/OFF, agenda un cambio controlado. El día después de un reboot no limpio no es el momento para descubrir que no puedes recuperar relay logs correctamente.
Tarea 12: Detectar ruptura por clave duplicada (clásico tras una promoción incorrecta)
cr0x@server:~$ mysql -e "SHOW SLAVE STATUS\G" | egrep "Last_SQL_Errno|Last_SQL_Error|Slave_SQL_Running"
Slave_SQL_Running: No
Last_SQL_Errno: 1062
Last_SQL_Error: Error 'Duplicate entry '1842' for key 'PRIMARY'' on query. Default database: 'app'. Query: 'INSERT INTO users(id,...) VALUES(...)'
Qué significa: La réplica aplicó algo fuera de orden o divergió. A menudo causado por escribir en una réplica, o por promover una réplica que no tenía transacciones.
Decisión: Para. No saltes errores a ciegas. Identifica el alcance de la divergencia: compara conjuntos/posiciones GTID, ejecuta comprobaciones de consistencia y considera reconstruir la réplica desde una snapshot conocida buena.
Tarea 13: Verificar que nadie escribe en réplicas (sucede)
cr0x@server:~$ mysql -e "SHOW VARIABLES LIKE 'read_only'; SHOW VARIABLES LIKE 'super_read_only';"
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| read_only | OFF |
+---------------+-------+
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| super_read_only | OFF |
+-----------------+-------+
Qué significa: La réplica es escribible. Esto está bien solo si lo haces intencionalmente (raro) y entiendes las consecuencias.
Decisión: Activa read_only y super_read_only en réplicas por política. Si una app necesita escribir, necesita otra arquitectura, no una excepción sigilosa.
Tarea 14: Comprobar filtros de replicación que silenciosamente descartan datos
cr0x@server:~$ mysql -e "SHOW VARIABLES LIKE 'replicate%';" | egrep -v "replicate_(same_server_id|rewrite_db)"
replicate_do_db app
replicate_ignore_db mysql
replicate_wild_ignore_table app.tmp_%
Qué significa: Estás filtrando replicación. Esto puede ser válido, pero es peligroso con consultas cross-db y DDL.
Decisión: Audita cada filtro contra los patrones reales de carga. Si no puedes probar que es seguro, elimínalo y aisla datos de otra manera (instancias separadas, clusters separados).
Guion de diagnóstico rápido
Cuando la replicación está “lenta” o “rota”, tu trabajo no es mirar un métrico. Tu trabajo es encontrar el recurso limitante
y el modo de fallo rápido, luego elegir la intervención menos arriesgada.
Primero: ¿La replicación está parada o mintiendo?
- Revisa
SHOW SLAVE STATUS\G(o equivalente) en busca de IO/SQL corriendo y errores. - Si ambos threads corren, no asumas corrección. Valida lag vía heartbeat y verificaciones de datos muestreados.
Segundo: ¿El cuello de botella es red, disco o locks?
- Red/hilo IO: hilo IO no corriendo, “connecting” o “reconnecting”.
- Disco/commit: hilo SQL esperando commit, alto
iostatawait, %util saturado. - Locks/DDL: hilo SQL atascado en metadata locks; DDL de larga duración bloquea el apply.
Tercero: ¿Es un desajuste de formato/compatibilidad?
- Comprueba formato de binlog y variables de checksum en ambos extremos.
- Revisa desfase de versiones, diferencias de plugins y compatibilidad de modo GTID.
Cuarto: Decide el nivel de intervención
- Bajo riesgo: limitar escrituras, añadir espacio en disco, arreglar red, mejorar IO.
- Riesgo medio: ajustar workers paralelos o aplicar tuning con medición.
- Alto riesgo: saltar errores, resetear slave, reconstruir réplicas, promover otro nodo. El alto riesgo requiere un plan por escrito y rollback.
Errores comunes: síntomas → causa raíz → solución
1) “Seconds_Behind_Master es 0, pero los datos son incorrectos”
Síntoma: Lecturas de la app desde réplicas muestran filas faltantes o agregados obsoletos; el estado de replicación parece “correcto”.
Causa raíz: Deriva por replicación basada en sentencias, funciones inseguras o filtros que descartan eventos; a veces escrituras filtradas hacia réplicas.
Solución: Cambia a binlog basado en filas cuando sea posible; elimina filtros riesgosos; impone super_read_only; ejecuta comprobaciones de consistencia y reconstruye réplicas divergentes.
2) “La replicación se rompió tras una actualización menor”
Síntoma: hilo IO se detiene con errores de parseo de eventos; o hilo SQL falla por tipos de evento desconocidos.
Causa raíz: Desfase de versiones que emite características de binlog que la réplica no puede parsear; mismatch de checksum; incompatibilidad de modo GTID entre sabores.
Solución: Alinea versiones dentro de rangos soportados; estandariza binlog_checksum; valida la compatibilidad de GTID en un laboratorio y en una réplica canaria antes del despliegue.
3) “El lag crece durante ráfagas de escritura y no se recupera”
Síntoma: los relay logs se inflan; el hilo SQL muestra “Waiting for handler commit”; IO está caliente.
Causa raíz: El disco de la réplica es el cuello de botella (presión de fsync, almacenamiento saturado), no la CPU. RBR aumenta la amplificación de escritura.
Solución: Mueve réplicas a almacenamiento más rápido; ajusta la configuración de logs de InnoDB; asegura dimensionamiento del buffer pool; considera retrasar consultas analíticas pesadas en réplicas.
4) “Hicimos failover con GTID y aún perdimos transacciones”
Síntoma: usuarios reportan escrituras recientes faltantes; el primario murió; el nuevo primario fue promovido limpiamente.
Causa raíz: Ventana de replicación asíncrona, reconocimiento semi-sync solo en recibo, o réplica promovida no completamente al día/aplicada.
Solución: Lleva la promoción condicionada a estado verificado de catch-up; si usas semi-sync, asegura que tu failover promueva la réplica reconocida cuando sea posible; endurece ajustes de durabilidad donde se requiera.
5) “La replicación paralela lo empeoró”
Síntoma: aumentar workers incrementa lag y CPU; el rendimiento de replicación cae.
Causa raíz: Contención, filas calientes, serialización de commits, churn del buffer pool o DDL que bloquea el apply.
Solución: Reduce workers; perfila esperas; trata DDL como evento programado; shardea hotspots de escritura si es necesario; valida el tuning bajo carga realista.
6) “La réplica se cae y vuelve rota”
Síntoma: Tras el reboot, la réplica no puede reanudar; relay logs inconsistentes; requiere reposicionamiento manual.
Causa raíz: Repositorios de metadatos no crash-safe; recuperación de relay log desactivada; problemas de filesystem/disco.
Solución: Habilita repositorios crash-safe (TABLE) y recuperación de relay log; valida salud del filesystem; reconstruye la réplica si el estado es sospechoso.
Tres micro-historias corporativas desde las trincheras de replicación
Micro-historia 1: El incidente causado por una suposición equivocada
Una compañía SaaS mediana tenía un estate mixto: MariaDB para una línea de producto legacy, Percona Server para servicios más nuevos.
Un equipo heredó una topología de replicación entre centros de datos y estandarizó el runbook de failover alrededor de “GTID auto-positioning.”
Asumieron que GTID era GTID. Mismo acrónimo, misma seguridad, mismo resultado.
Durante una caída del primario, promovieron una réplica usando los pasos que funcionaban sin problemas en Percona.
La replicación se reanudó, la app se recuperó, los dashboards se pusieron en verde. Todos exhalaron.
Luego comenzaron las escalaciones de soporte: cambios recientes en suscripciones faltaban, pero solo para algunos tenants.
El postmortem fue dolorosamente educativo. El estado de GTID de MariaDB no se interpretaba como esperaba la herramienta de failover.
La herramienta eligió un candidato de promoción que parecía al día por una métrica pero no era el nodo “más avanzado” correcto
según las semánticas de dominio GTID de MariaDB.
Podrían haberlo detectado con un preflight: validar conjuntos de transacciones ejecutadas usando las variables de servidor correctas,
y probar el failover cross-flavor en un laboratorio con binlogs reales. En vez de eso, lo aprendieron en producción, que es la aula más cara.
La solución no fue heroica. Dividieron los playbooks operativos por sabor, impusieron monitorización específica por sabor y dejaron de fingir
que un script de automatización universal podía manejar ambos sin lógica explícita de compatibilidad.
Micro-historia 2: La optimización que salió mal
Una empresa de e-commerce tenía un dolor familiar: las réplicas sufrían lag durante promociones.
Alguien propuso un tweak simple: relajar durabilidad para acelerar commits y dejar que las réplicas se pongan al día.
Bajaron sync_binlog y cambiaron ajustes de flush de logs en réplicas también, porque “las réplicas no necesitan ser tan durables”.
El lag mejoró por un tiempo. El equipo celebró con la satisfacción silenciosa de recortar milisegundos del gráfico.
Luego un host réplica se reinició durante una actualización de kernel, y la réplica volvió con relay logs en los que no se podía confiar.
La recuperación requirió intervención manual y luego una reconstrucción.
Durante la ventana de reconstrucción, las réplicas restantes asumieron más tráfico de lectura y más carga de replicación.
El lag volvió, ahora con menos redes de seguridad. Habían optimizado para el estado estable mientras aumentaban el radio de explosión en eventos rutinarios.
La lección no fue “nunca tunear”. Fue “tunear con un modelo de fallos”. Si bajas durabilidad, debes modelar qué pasa ante crash,
pérdida de energía y failover. Si tu modelo es “probablemente está bien”, felicidades: has adoptado ingeniería folklórica.
Revirtieron los ajustes riesgosos, movieron réplicas a discos más rápidos y dejaron de usar perillas de durabilidad como parche de rendimiento.
El almacenamiento era el cuello de botella todo el tiempo—como suele ocurrir.
Micro-historia 3: La práctica aburrida pero correcta que salvó el día
Una plataforma de pagos ejecutaba Percona Server con disciplina operativa estricta.
Tenían un ritual semanal: validar catch-up de réplicas, ejecutar una pasada de checksums en un subconjunto rotativo de tablas,
ensayar una promoción controlada en un entorno staging que replicaba la configuración de producción y registrar los comandos exactos.
Nadie se jactaba. No era “innovación”. Era mantenimiento.
Una tarde, un nodo primario empezó a lanzar stalls de fsync intermitentes. El lag de replicación comenzó a subir.
El on-call siguió el guion de diagnóstico rápido y confirmó que el problema era latencia de almacenamiento, no locks SQL.
Limitaron un batch writer, drenaron tráfico y se prepararon para fallover.
La diferencia fue la puerta de promoción: promovieron solo una réplica verificada al día vía heartbeat y estado de transacciones,
y tenían una checklist preaprobada para asegurar flags de solo-lectura y ajustes de binlog correctos en el nuevo primario.
El failover fue poco glamoroso. También fue limpio. Sin transacciones faltantes, sin deriva, sin búsqueda de “por qué esta tabla es diferente”.
Su mayor estrés fue esperar TTLs de DNS, que es el tipo correcto de estrés.
La fiabilidad es mayormente un montón de hábitos aburridos. Lo aburrido está subestimado.
Una cita que vale la pena tener en la pared
Idea parafraseada (atribuida a Richard Cook): “El éxito viene de adaptarse a las sorpresas; el fracaso viene de un mismo sistema operando bajo tensión.”
Listas de verificación / plan paso a paso
Checklist A: Diseñar replicación para que los casos límite duelan menos
- Elige una estrategia de sabor: solo MariaDB GTID, solo MySQL/Percona GTID, o sin GTID con posiciones explícitas. Evita “lo vemos después”.
- Estandariza formato de binlog (preferir ROW) y checksum de binlog en toda la flota.
- Decide tu postura de durabilidad y documenta el RPO. Alinea
sync_binlogyinnodb_flush_log_at_trx_commitcon esa decisión. - Habilita metadatos de replicación crash-safe (
master_info_repository=TABLE,relay_log_info_repository=TABLE,relay_log_recovery=ON) donde sea soportado y probado. - Impone read-only en réplicas (
read_onlyysuper_read_only). - Elige un método de medición de lag que refleje la realidad (basado en heartbeat).
- Decide cómo se despliegan los DDL (ventanas programadas, herramientas online o patrones de migración a nivel aplicación).
Checklist B: Procedimiento de promoción / failover (versión segura para humanos)
- Congela escrituras si puedes (modo mantenimiento de la app o limitación de escritor). Si no puedes, al menos conoce tu ventana esperada de pérdida.
- Elige candidato de promoción basado en catch-up verificado: lag de heartbeat cercano a cero, threads de replicación sanos, sin errores SQL.
- Verifica el estado de transacciones usando variables de GTID/posición correctas para el sabor. No “traduce en tu cabeza”.
- Confirma que el candidato no sea escribible antes de promover salvo que sea necesario. Luego actívalo intencionalmente.
- Promueve: detén replicación limpiamente, resetea la config de replicación según sea necesario, asegura que el binlog esté habilitado en el nuevo primario.
- Apunta las demás réplicas al nuevo primario usando el método de auto-position correcto para tu sabor.
- Valida la corrección con chequeos puntuales y una pequeña prueba de consistencia. Luego descongela escrituras.
Checklist C: Cuando debes reconstruir una réplica (y lo harás)
- Detén la replicación y registra la salida de estado actual para la línea de tiempo del incidente.
- Elige una fuente de snapshot limpia (preferir una réplica verificada correcta, no “la menos rota”).
- Restaura datos y luego establece coordenadas/estado GTID cuidadosamente.
- Inicia replicación y vigila errores SQL tempranos (duplicados, tablas faltantes, issues de checksum).
- Ejecuta una comprobación de consistencia dirigida en tablas de alto valor antes de ponerla en servicio.
Chiste #2
Los filtros de replicación son como la política de oficina: parecen útiles hasta que te das cuenta de que han estado descartando información importante en silencio.
Preguntas frecuentes
1) ¿Puede MariaDB replicar desde Percona Server (o viceversa) de forma segura?
A veces, en combinaciones de versiones y configuraciones específicas, pero “de forma segura” requiere probar tu formato de binlog exacto,
modo de checksum y estrategia GTID. GTID cross-flavor es donde los equipos se lastiman. Si debes mezclar, hacelo con un laboratorio que reproduzca binlogs reales.
2) ¿Debo usar GTID en todas partes?
Sí si tus herramientas y procedimientos de equipo son nativos GTID para el sabor elegido. No si estás mezclando sabores sin un plan de compatibilidad.
GTID mejora la ergonomía del failover, pero no elimina ventanas de pérdida de datos ni malas decisiones de promoción.
3) ¿La replicación semi-sync es “sin pérdida de datos”?
No. Reduce la ventana asegurando que al menos una réplica recibió el evento antes del ACK al cliente, pero el recibo no es aplicación.
Aún puedes perder transacciones dependiendo del timing del crash y la elección de failover.
4) ¿Por qué el lag se dispara durante DDL incluso con replicación paralela?
El DDL a menudo serializa la ejecución y puede tomar metadata locks que bloquean el apply. Los workers paralelos no pueden avanzar más allá de un evento bloqueante.
Trata los cambios de esquema grandes como eventos planeados y pruébalos bajo carga similar a producción.
5) ¿Cuál es la métrica de lag más fiable para decisiones de failover?
Las mediciones basadas en heartbeat (p. ej., una marca temporal escrita en el primario y leída en réplicas) suelen ser más veraces que
Seconds_Behind_Master, especialmente bajo apply paralelo o cuando el hilo SQL está bloqueado intermitentemente.
6) Si la replicación está rota, ¿debo saltarme la transacción que falla?
Solo como último recurso, y solo cuando entiendas completamente lo que estás saltando y cómo repararás la consistencia.
Saltarse es un instrumento de deuda operativa con intereses compuestos.
7) ¿Por qué divergen las réplicas incluso cuando la replicación dice que está corriendo?
Causas comunes: replicación basada en sentencias con no determinismo, escrituras filtradas a réplicas, filtros de replicación y
comportamiento de la aplicación que depende de settings de sesión que no se replican como se espera. La divergencia suele ser una falla de política, no un misterio.
8) ¿Cuál es la forma más rápida de saber si el cuello de botella es almacenamiento?
Si los estados de hilos SQL muestran esperas por commit y iostat muestra alto await/%util, es almacenamiento. Arregla almacenamiento o reduce presión de escritura.
No “optimices” los threads de replicación contra una pared de disco.
9) ¿Las características específicas de Percona cambian el comportamiento de replicación?
Percona Server típicamente está cerca de las semánticas de replicación de Oracle MySQL, pero la instrumentación extra y los knobs pueden cambiar el comportamiento de rendimiento.
Trátalo como un sabor de primera clase: mantén configuraciones consistentes y prueba upgrades, especialmente en torno a replicación paralela y durabilidad.
10) ¿Cuál es la elección de formato de binlog más segura hoy?
La replicación basada en filas es la opción habitual por corrección. El coste es mayor volumen de binlog y más IO en réplicas.
Si eliges basado en sentencias, necesitas controles estrictos sobre patrones SQL y alta tolerancia a “deriva sorpresa”.
Siguientes pasos que puedes hacer esta semana
Si quieres menos incidentes de replicación, no comiences debatiendo marcas. Comienza por eliminar ambigüedad.
- Inventaria sabores y versiones en toda tu topología. Escríbelo. Deja de asumir “es todo MySQL”.
- Estandariza formato de binlog y checksum y verifica con comandos en cada nodo.
- Decide y documenta tu RPO, luego alinea ajustes de durabilidad con ello. Si el negocio no decide, elige ajustes conservadores y hazles pagar la factura de latencia.
- Implementa medición de lag basada en heartbeat y úsala en alertas y gates de failover.
- Ejecuta un ensayo de failover controlado en staging con configuraciones parecidas a producción. Mídelo. Arregla los pasos que requieran conocimiento tribal.
- Elige una “práctica aburrida de corrección” (enforce read-only, metadatos de replicación crash-safe, checks semanales de consistencia) y conviértela en política.
Los casos límite de replicación no importan qué distribución instalaste. Les importa qué asumiste, qué probaste
y qué estás dispuesto a mantener consistente cuando nadie está mirando.