No migras bases de datos porque te aburres. Migras porque te topaste con un muro: escalado de escrituras, latencia entre regiones, sobrecarga operativa, conteos de shards que explotan, o una fecha límite de cumplimiento que no respeta tus planes de fin de semana.
MariaDB y TiDB aparecen en la conversación de “necesitamos comportamiento tipo MySQL pero mejor”. La historia de marketing es atractiva: conserva SQL, gana escala, reduce el dolor. La realidad en producción es más desordenada: modos de fallo distintos, controles distintos y maneras diferentes de arruinar tu rotación de on-call. Hablemos de eso.
Lo que realmente eliges (no una base de datos)
“MariaDB vs TiDB” suena como una comparación de productos. En producción, en realidad es una elección entre dos modelos operativos:
- MariaDB es un motor InnoDB de nodo único conocido con patrones de replicación maduros (replicación asíncrona, semi-sync, GTID y en algunas implementaciones Galera). Puedes ejecutarlo de forma aburrida y bien. También puedes ejecutarlo “de forma creativa” y aprender nuevos sinónimos de dolor.
- TiDB es SQL distribuido: nodos de cómputo (TiDB), nodos de almacenamiento (TiKV) y un plano de control (PD). Compras escalado horizontal y alta disponibilidad por diseño—más el impuesto de complejidad de un sistema distribuido. Cada pregunta “simple” se convierte en “¿qué capa y qué componente está mintiendo?”
Aquí está la decisión que impulso en organizaciones reales:
- Si tu cuello de botella son uno o unos pocos primarios saturados, pero tu carga es aún mayormente OLTP en una sola región, y puedes escalar verticalmente y con réplicas de lectura, MariaDB sigue siendo difícil de superar por su simplicidad operativa.
- Si ya vives en el infierno de shards, o necesitas escalar escrituras entre nodos con consistencia fuerte y latencia aceptable, TiDB puede ser la opción adulta—si inviertes en observabilidad y madurez SRE.
Una idea parafraseada de Werner Vogels (CTO de Amazon) que aún se mantiene: todo falla, todo el tiempo; el trabajo es diseñar de modo que el sistema siga funcionando de todos modos
(idea parafraseada).
La cita encaja claramente: MariaDB trata de diseñar límites de fallo alrededor de una verdad mayormente de nodo único. TiDB trata de diseñar alrededor de fallos parciales constantes en muchos nodos.
Hechos históricos rápidos que realmente importan
Algunos puntos de contexto que cambian cómo operas estos sistemas. Corto. Concreto. Útil.
- MariaDB se bifurcó de MySQL en 2009 después de que Oracle adquiriera Sun; ese origen explica por qué la compatibilidad es una preocupación de primera clase y por qué “mayormente como MySQL” forma parte del ADN de la marca.
- InnoDB se convirtió en el motor de almacenamiento por defecto en MySQL años antes de que muchos equipos dejáramos de pensar en términos de MyISAM. Si tu aplicación heredada aún asume el comportamiento de bloqueo a nivel de tabla, ya estás jugando en modo difícil.
- Galera “multi-master” es realmente replicación síncrona con certificación. No es magia. Cambia concurrencia de escritura por orden global y puede castigar filas calientes.
- La arquitectura de TiDB se inspiró en el estilo Spanner/F1 de Google (sin TrueTime). La parte importante es la separación entre SQL sin estado y KV con estado.
- TiKV usa replicación Raft. Eso significa escrituras por quórum, problemas de colocación de líderes e historias de “un disco lento puede ralentizar una región”.
- PD (Placement Driver) es una dependencia real del plano de control. Si lo tratas como “solo otro servicio”, te encontrarás con él a las 3 a.m.
- La compatibilidad con MySQL es un objetivo móvil para TiDB. Una consulta que funciona no es lo mismo que una consulta que tiene el mismo comportamiento operativo. La superficie SQL no es equivalencia operacional.
- Los cambios de esquema en línea en el mundo MySQL evolucionaron como un mecanismo de afrontamiento. Existen herramientas y patrones porque “ALTER TABLE” ha estado castigando a la gente desde siempre.
Arquitectura en términos operativos: dónde viven los dragones
MariaDB: un motor, muchas formas de replicarlo
El troubleshooting de rendimiento en MariaDB aún se siente familiar para la mayoría de SREs: CPU, buffer pool, latencia de IO, contención de mutex, consultas malas, índices faltantes y lag de replicación. Cuando arde, normalmente arde en un solo lugar.
Incluso en configuraciones en clúster (Galera), tu unidad de dolor sigue siendo “el nodo de la base de datos”. Puedes medirlo, aislarlo, reemplazarlo. Las partes difíciles son:
- Semánticas de replicación: asíncrona implica lag y posible pérdida al hacer failover; semi-sync reduce pérdida pero aumenta latencia; Galera implica manejo de conflictos y control de flujo.
- Cambios de esquema: existen DDL en línea, pero no todo es en línea, y las tablas grandes encontrarán los bordes afilados.
- Escalado de escrituras: escalas escrituras subiendo recursos, reduciendo amplificación de escritura o cambiando la aplicación. “Solo agrega nodos” es mayormente una historia de lectura.
TiDB: nodos SQL sin estado + almacenamiento Raft + un plano de control
TiDB reparte tu base de datos en capas:
- TiDB (capa SQL): parsea SQL, planifica consultas, empuja trabajo hacia abajo y maneja transacciones distribuidas.
- TiKV (almacenamiento): guarda datos key/value en regiones, cada una replicada por Raft. Los líderes importan. La red importa. El disco importa. La compactación importa.
- PD: programa regiones, balancea líderes, provee timestamps y decisiones de colocación.
Esa separación es por qué TiDB puede escalar lecturas y escrituras. También es por qué puedes tener un “incidente de base de datos” donde la CPU está bien, las consultas están bien, y el verdadero villano es un solo nodo TiKV con IO miserable, provocando elecciones de líderes y reintentos de transacciones.
Verdad seca: una base de datos distribuida es una base de datos más un currículo de sistemas distribuidos que te verás forzado a tomar durante los incidentes. El examen siempre tiene tiempo límite.
Broma #1: Las bases de datos distribuidas son geniales porque convierten un disco lento en un ejercicio de construcción de equipo entre tres servicios.
Promesas de migración frente a lo que se rompe primero
Promesa: “Es compatible con MySQL, así que la app simplemente funciona”
La compatibilidad te ayuda con el parsing. No te ayuda con el comportamiento en producción:
- Los planes de consulta divergen. Una consulta “bien” en MariaDB con un optimizador de nodo único puede convertirse en una fiesta de escaneo de tabla distribuida en TiDB.
- Los patrones de transacción importan más. Transacciones largas, actualizaciones por lotes grandes y claves calientes exponen contención en Raft y comportamiento MVCC.
- El comportamiento de DDL difiere. TiDB admite patrones de DDL en línea, pero operativamente aún debes planificar la carga de backfill y la programación de PD.
Promesa: “TiDB elimina la complejidad del sharding”
Sí, pero lo cambias por otra complejidad:
- El hotspot es el nuevo shard. En lugar de “user_id módulo N”, obtienes “este líder de región se está derritiendo”.
- La planificación de capacidad es por capas. Los nodos de cómputo escalan diferente a los nodos de almacenamiento. Tu factura y tu cuello de botella pueden no coincidir.
- Las dependencias operacionales se expanden. Ahora operas un plano de control, una capa de almacenamiento y nodos SQL sin estado.
Promesa: “El clúster MariaDB da HA y escala”
¿HA? Absolutamente, cuando se hace bien. ¿Escala de escritura? Con cautela. En Galera, cada nodo debe certificar escrituras; cargas pesadas de escritura pueden sufrir conflictos y control de flujo. La replicación asíncrona puede escalar lecturas fácilmente, pero las escrituras aún se canalizan por un primario.
Promesa: “Podemos migrar con tiempo de inactividad mínimo”
Puedes, pero el trabajo crítico no es copiar los datos. Es el trabajo de compatibilidad de comportamiento:
- Modos SQL y conversiones implícitas de tipos
- Suposiciones sobre niveles de aislamiento
- Uso de funciones no determinísticas
- Procedimientos almacenados, triggers y patrones de DDL en casos límite
- Runbooks operativos: backups, restores, failovers, DR
Realidades de producción: rendimiento, corrección y sueño
Realidad de rendimiento #1: la latencia tiene nuevos pisos
MariaDB puede ser muy rápida en OLTP de una sola fila cuando los datos están en el buffer pool y no estás limitado por IO. TiDB añade saltos de red y commits por quórum. Eso no significa que TiDB sea “lento”; significa que la latencia p99 tiene una física distinta.
Si tu producto requiere p99 de escritura por debajo de 5 ms en una sola AZ, TiDB aún puede funcionar, pero sudarás por la colocación, la localidad de líderes y el diseño de transacciones. Si ya estás en 20–50 ms p99 porque tu app hace muchas llamadas, la sobrecarga de TiDB podría quedar oculta bajo decisiones malas existentes.
Realidad de rendimiento #2: los hotspots son inevitables
En MariaDB, los hotspots son mayormente bloqueos y contención de índices. En TiDB, los hotspots a menudo se manifiestan como:
- Una región recibiendo la mayoría de las escrituras por claves secuenciales
- Un líder concentrado en un TiKV
- Patrones de acceso sesgados que hacen que PD persiga el balance perpetuamente
Realidad de corrección: las semánticas “multi-master” son distintas
La replicación síncrona de Galera significa que una transacción debe certificarse a nivel de clúster; los conflictos ocurren al commitear y la lógica de reintento importa. TiDB ofrece consistencia fuerte vía replicación Raft y MVCC, pero las transacciones distribuidas amplifican el coste de la contención y de las transacciones de larga duración.
Realidad operativa: los backups y restores son donde se pierde la confianza
Toda base de datos puede hacer backup. La pregunta es: ¿puedes restaurar rápida y correctamente bajo presión? Los dumps lógicos de MariaDB son portables pero pueden ser lentos; los backups físicos son rápidos pero requieren disciplina. Los backups de TiDB involucran estado distribuido grande; las restauraciones deben considerar colocación, carga y compatibilidad de versiones.
Broma #2: Un backup es el archivo de Schrödinger: es válido y inútil hasta que intentas una restauración.
Guía rápida de diagnóstico
Esta es la secuencia “deja de debatir arquitectura y encuentra el cuello de botella” que uso. Hazlo en orden. No improvises hasta tener evidencia.
Primero: ¿es la app, la red o la base de datos?
- Revisa el desglose de latencia de extremo a extremo. Si no lo tienes, extráelo del tracing de la app o al menos compara tiempo DB vs tiempo total de la petición.
- Confirma saturación. ¿CPU al máximo? ¿espera de IO? ¿retransmisiones de red? Si nada está saturado, persigues contención o regresiones de plan.
- Confirma el patrón de concurrencia. Picos de conexiones, pools de hilos, profundidades de cola.
Segundo: decide si el cuello de botella está en “capa SQL” o “capa de almacenamiento”
- MariaDB: revisa métricas InnoDB, slow log, buffer pool, lag de replicación.
- TiDB: revisa CPU de TiDB y duración de consultas, luego IO/CPU de TiKV y métricas raftstore, luego programación PD y balance de líderes.
Tercero: clasifica el modo de fallo
- Regresión de plan: cambio repentino en latencia de consultas tras un deploy/cambio de esquema.
- Contención: esperas de lock, deadlocks, stalls de escritura Raft, regiones calientes.
- Capacidad: latencia de disco, deuda de compactación, misses de buffer pool, stalls de rocksdb en TiKV.
- Plano de control: PD no disponible, programación atascada, problemas de metadata.
- Replicación/failover: lag, elecciones, prevención de split brain activándose.
Cuarto: elige la palanca más rápida para “reducir carga” mientras diagnosticas
- Limita la tasa de los endpoints más calientes.
- Desactiva jobs background costosos.
- Aumenta temporalmente los timeouts del pool de conexiones para evitar avalanchas.
- En TiDB, considera mover líderes fuera de un TiKV enfermo y reducir la presión de hotspots.
Tareas prácticas (comandos, salidas, decisiones)
A continuación hay tareas reales que puedes ejecutar durante la planificación de migración, depuración de rendimiento y respuesta a incidentes. Cada una incluye: comando, salida de ejemplo, qué significa y qué decisión tomar.
Tarea 1: Confirmar versión de MariaDB, variables del servidor y conceptos del motor
cr0x@server:~$ mysql -h mariadb01 -uroot -p -e "SELECT VERSION(); SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; SHOW VARIABLES LIKE 'log_bin';"
Enter password:
VERSION()
10.11.6-MariaDB-1:10.11.6+maria~ubu2204
Variable_name Value
innodb_buffer_pool_size 17179869184
Variable_name Value
log_bin ON
Significado: Estás en MariaDB 10.11, el buffer pool es de 16GiB, binlog habilitado.
Decisión: Si dependes de CDC o réplicas asíncronas, binlog debe permanecer activado. Si estás limitado por IO y no necesitas binlog, esa es una conversación mayor—no “optimices” eliminando tu camino de recuperación.
Tarea 2: Detectar eventos de espera y dolor por locks en MariaDB
cr0x@server:~$ mysql -h mariadb01 -uroot -p -e "SHOW ENGINE INNODB STATUS\G" | sed -n '1,120p'
Enter password:
*************************** 1. row ***************************
Type: InnoDB
Name:
Status:
=====================================
2025-12-30 10:41:23 0x7f5a2c1ff700 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 28 seconds
-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 714 srv_active, 0 srv_shutdown, 1082 srv_idle
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 24417
--Thread 140025024026368 has waited at row0lock.cc line 1134 for 12.00 seconds the semaphore:
Significado: Hilos esperan por row locks; probablemente hay contención o una transacción mantiene locks demasiado tiempo.
Decisión: Encuentra la transacción bloqueante (tarea siguiente) y decide: matarla, reducir tamaño de lote, añadir índice o reescribir el patrón de actualización.
Tarea 3: Identificar transacciones de larga duración en MariaDB
cr0x@server:~$ mysql -h mariadb01 -uroot -p -e "SELECT trx_id, trx_started, trx_mysql_thread_id, trx_query FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 5\G"
Enter password:
*************************** 1. row ***************************
trx_id: 9A3F2B11
trx_started: 2025-12-30 10:12:01
trx_mysql_thread_id: 18841
trx_query: UPDATE orders SET status='CLOSED' WHERE customer_id=412993;
Significado: Una transacción ha estado abierta ~30 minutos. Eso puede bloquear purge y otros escritores.
Decisión: Si es seguro, mata la sesión y corrige la lógica de la aplicación para evitar transacciones largas (commit más frecuente, lotes más pequeños).
Tarea 4: Confirmar estado de replicación y lag en MariaDB
cr0x@server:~$ mysql -h mariadb-replica01 -uroot -p -e "SHOW SLAVE STATUS\G" | egrep "Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master|Using_Gtid"
Enter password:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 37
Using_Gtid: Slave_Pos
Significado: La réplica está saludable pero ~37 segundos detrás.
Decisión: Si tu RTO/RPO no tolera 37 segundos, necesitas semi-sync, mejor hardware, menor carga de escritura o topología distinta.
Tarea 5: Comprobar formato de binlog para suposiciones de migración/CDC
cr0x@server:~$ mysql -h mariadb01 -uroot -p -e "SHOW VARIABLES LIKE 'binlog_format';"
Enter password:
Variable_name Value
binlog_format ROW
Significado: Binlog en formato ROW habilitado; bueno para muchos pipelines CDC.
Decisión: Mantén ROW para corrección a menos que tengas una razón probada para cambiar. Binlogs basados en statement más consultas no determinísticas es cómo obtienes “creatividad” en réplicas.
Tarea 6: Mostrar consultas lentas en MariaDB (con evidencia real)
cr0x@server:~$ sudo tail -n 20 /var/log/mysql/slow.log
# Time: 2025-12-30T10:38:13.512345Z
# User@Host: app[app] @ 10.20.3.14 []
# Query_time: 2.871 Lock_time: 0.004 Rows_sent: 25 Rows_examined: 1820031
SELECT * FROM orders WHERE created_at >= '2025-12-01' ORDER BY created_at DESC LIMIT 25;
Significado: Gran escaneo (1.8M filas examinadas) para devolver 25 filas. Clásico índice faltante o patrón de acceso incorrecto.
Decisión: Añade un índice que cubra (por ejemplo, en created_at más columnas de filtro) o rediseña la consulta para evitar ordenar rangos grandes.
Tarea 7: Validar uso de índice con EXPLAIN en MariaDB
cr0x@server:~$ mysql -h mariadb01 -uroot -p -e "EXPLAIN SELECT * FROM orders WHERE created_at >= '2025-12-01' ORDER BY created_at DESC LIMIT 25\G"
Enter password:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: orders
type: ALL
possible_keys: idx_created_at
key: NULL
rows: 1900000
Extra: Using where; Using filesort
Significado: Escaneo completo de tabla y filesort; índice no usado.
Decisión: Arregla el índice o la consulta. Si el índice existe pero no se usa, revisa mismatch de collation/tipo, funciones sobre la columna o estadísticas de cardinalidad pobres.
Tarea 8: Snapshot de salud del clúster TiDB (sanidad del plano de control)
cr0x@server:~$ tiup ctl:v8.5.0 pd -u http://pd01:2379 store
{
"count": 3,
"stores": [
{ "store": { "id": 1, "address": "tikv01:20160", "state_name": "Up" } },
{ "store": { "id": 2, "address": "tikv02:20160", "state_name": "Up" } },
{ "store": { "id": 3, "address": "tikv03:20160", "state_name": "Up" } }
]
}
Significado: PD es accesible; stores TiKV están Up.
Decisión: Si PD no responde rápido, deja de culpar al SQL. Estabiliza PD/quórum primero; todo depende de ello.
Tarea 9: Detectar regiones hotspot en TiDB/TiKV (donde se esconden los “shards”)
cr0x@server:~$ tiup ctl:v8.5.0 pd -u http://pd01:2379 hot read
{
"as_leader": [
{ "region_id": 74219, "store_id": 2, "hot_degree": 97, "flow_bytes": 183274112 }
]
}
Significado: El store 2 es líder de una región muy caliente. Espera latencia desigual y CPU alta en ese nodo.
Decisión: Investiga patrón de acceso (claves secuenciales, inserciones time-series o un solo tenant). Considera dividir regiones, cambiar el diseño de claves o mover líderes como mitigación.
Tarea 10: Comprobar balance de líderes y programación en TiDB (¿PD está haciendo su trabajo?)
cr0x@server:~$ tiup ctl:v8.5.0 pd -u http://pd01:2379 scheduler show
[
"balance-leader-scheduler",
"balance-region-scheduler",
"balance-hot-region-scheduler"
]
Significado: Los schedulers esperados están habilitados.
Decisión: Si balance-hot-region-scheduler falta/está deshabilitado, los hotspots persistirán. Habilítalo solo si entiendes los efectos secundarios en estabilidad durante picos.
Tarea 11: Detectar reintentos de transacción y contención de latch desde la capa SQL de TiDB
cr0x@server:~$ mysql -h tidb01 -P4000 -uroot -e "SHOW STATUS LIKE 'tidb_txn_retry%'; SHOW STATUS LIKE 'tidb_server_execute%';"
Variable_name Value
tidb_txn_retry_total 1842
Variable_name Value
tidb_server_execute_duration_seconds_count 1298821
Significado: Reintentos de transacción no triviales. A menudo es contención, conflictos o respuestas lentas del almacenamiento.
Decisión: Si los reintentos suben durante incidentes, prioriza comprobaciones de hotspot y salud del almacenamiento sobre trivialidades de tuning SQL.
Tarea 12: Confirmar salud de disco y IO wait en un TiKV sospechoso
cr0x@server:~$ ssh tikv02 "iostat -x 1 3 | tail -n +4"
Device r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await %util
nvme0n1 210.4 488.7 12.1 44.8 121.3 8.72 15.90 98.7
Significado: El disco está casi saturado (%util ~99) con await elevado. TiKV en este nodo responderá lento; los líderes Raft aquí perjudicarán todo el clúster.
Decisión: Mueve líderes/regiones fuera de este store y arregla el almacenamiento (salud NVMe, sistema de archivos, vecino ruidoso, presión de compactación). Si es un volumen en la nube, revisa créditos de burst y límites de throughput.
Tarea 13: Validar plan de consulta en TiDB, no solo el texto de la consulta
cr0x@server:~$ mysql -h tidb01 -P4000 -uroot -e "EXPLAIN ANALYZE SELECT * FROM orders WHERE created_at >= '2025-12-01' ORDER BY created_at DESC LIMIT 25;"
+---------------------------+---------+---------+-----------+----------------------------+
| id | estRows | actRows | task | operator info |
+---------------------------+---------+---------+-----------+----------------------------+
| TopN_5 | 25.00 | 25 | root | order by:created_at, limit |
| └─TableFullScan_7 | 1.90e+6 | 1.82e+6 | cop[tikv] | keep order:false |
+---------------------------+---------+---------+-----------+----------------------------+
Significado: Se está realizando un escaneo completo en TiKV. El sistema distribuido está ejecutando fielmente lo incorrecto.
Decisión: Añade el índice correcto o reescribe. Si debes escanear, prográmalo fuera de pico y aísla mediante controles de recursos; no dejes que analítica se disfrace de OLTP.
Tarea 14: Comprobar uso de disco y crecimiento de MariaDB antes del corte de migración
cr0x@server:~$ sudo du -sh /var/lib/mysql; sudo df -h /var/lib/mysql
182G /var/lib/mysql
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p2 500G 412G 63G 87% /var/lib/mysql
Significado: Estás al 87% de uso de disco. Eso no es “bien”. Eso es “una reconstrucción de índice away de despertar al equipo”.
Decisión: Antes de que las herramientas de migración se ejecuten, amplía disco o limpia. Las migraciones amplifican necesidades temporales de espacio (DDL, backfill, logs, snapshots).
Tres micro-historias corporativas desde las trincheras
Micro-historia 1: El incidente causado por una suposición equivocada
La empresa estaba en mitad de una migración de MariaDB a TiDB. El plan fue conservador: dual-write por un tiempo, leer desde MariaDB y luego volcar lecturas a TiDB. El equipo estaba orgulloso de sus pruebas de compatibilidad SQL; la suite de integración pasó; los paneles estaban verdes.
Volcaron un pequeño porcentaje de tráfico de lectura a TiDB. En una hora, la latencia p99 se duplicó para un puñado de endpoints. Nada dramático, solo ese tipo de sangrado lento que arruina funnels de conversión y hace que los product managers descubran la frase “regresión de base de datos”.
La suposición: “Si una consulta está indexada en MariaDB, se comportará de forma similar en TiDB.” La realidad: la consulta usaba un índice compuesto en MariaDB debido a un patrón particular de selectividad, pero el plan de TiDB eligió un escaneo completo bajo esa distribución. Era SQL técnicamente correcto y resultados funcionalmente correctos—simplemente operacionalmente equivocado.
Durante la revisión del incidente, la lección dolorosa no fue “TiDB es malo.” Fue que no habían construido una puerta de validación de planes. Probaban corrección, no rendimiento. La solución fue aburrida: capturar las principales consultas, ejecutar EXPLAIN ANALYZE en ambos sistemas y bloquear migraciones cuando el plan cambiara a formas costosas sin aprobación explícita.
Lo que les salvó de repetirlo fue una regla única: si una consulta toca más de X filas o realiza un escaneo completo en TiDB, necesita un índice, una reescritura o un plan de aislamiento de recursos. Sin excepciones por “pero siempre ha ido bien”.
Micro-historia 2: La optimización que salió mal
Otro equipo ejecutaba MariaDB con réplicas y tenía un job de reporting periódico que hacía escaneos de rango grandes. Alguien decidió “optimizar” moviendo el job de reporting a una réplica y aumentando el paralelismo. El job terminó más rápido. Todos aplaudieron tímidamente en Slack.
Una semana después, ocurrió un failover durante un flap de red. La réplica promovida llevaba más lag del que el equipo había notado porque el job de reporting estaba golpeando mucho el IO y aplicando eventos de replicación lentamente. El failover tuvo éxito, pero sirvieron datos algo stale el tiempo suficiente como para que finanzas lo notara, y notar finanzas es el tipo de notificación que trae invitaciones en el calendario.
La causa raíz no fue “reporting en réplica”. Fue la combinación de: mayor carga de IO, menos margen para aplicar replicación y un proceso de failover que no hacía cumplir una puerta RPO (“no promover si lag > umbral”).
La solución no fue heroica. Limitaron la tasa del job de reporting, añadieron una réplica analítica dedicada con hardware distinto y hicieron que la automatización de failover comprobara explícitamente el lag de replicación. La lección: optimizaciones de rendimiento que ignoran las rutas de failover son solo outages con mejor PR.
Micro-historia 3: La práctica aburrida pero correcta que salvó el día
Una empresa que corría TiDB tenía una práctica rutinaria que a nadie le encantaba: simulacros trimestrales de restauración. No “ejecutamos un comando de backup”. Restauraciones reales en un entorno aislado, con consultas de validación y un runbook cronometrado.
Luego llegó el día: un error humano en un script de automatización borró la tabla equivocada en producción. El cambio fue detectado rápido, pero los datos se perdieron igual de rápido. El pánico intentó entrar.
Ejecutaron el runbook. Restauración a un clúster nuevo, validación de recuentos de filas y checksums para tablas críticas, y luego reorientaron la aplicación para el conjunto de datos afectado. No fue instantáneo, pero fue controlado. El incidente se midió en minutos de downtime, no en pánico existencial.
El postmortem no fue emocionante. Sin villano. Sin milagro. Solo evidencia de que las disciplinas aburridas—simulacros de restauración, objetivos RTO/RPO claros y procedimientos de corte probados—superan la inteligencia. El equipo mantuvo sus fines de semana, que es el KPI más raro de todos.
Errores comunes (síntoma → causa raíz → solución)
1) “TiDB es lento” (p95/p99 sube tras la migración)
Síntoma: Lecturas y escrituras más lentas; CPU no está al máximo; la app ve reintentos/timeouts.
Causa raíz: Colocación cross-AZ/región, líderes no locales o latencia de disco en un subconjunto de nodos TiKV. Los commits distribuidos pagan por el miembro de quórum más lento.
Solución: Hacer cumplir localidad (labels/placement rules), confirmar distribución de líderes y arreglar nodos de almacenamiento lentos. Medir latencia de commit Raft y await de disco.
2) Réplica MariaDB se atrasa “aleatoriamente” durante picos
Síntoma: Seconds_Behind_Master se dispara; lecturas quedan stale; aumenta riesgo de failover.
Causa raíz: Saturación de IO en la réplica, transacciones largas en el primario creando ráfagas grandes de binlog, o restricciones de apply single-threaded dependiendo de la configuración/carga.
Solución: Reducir amplificación de escritura (índices, tamaño de lote), asegurar margen IO en réplicas, considerar replicación paralela si aplica y poner puertas de failover basadas en lag.
3) Throughput de clúster Galera colapsa cuando aumenta concurrencia de escritura
Síntoma: Añadir nodos no aumenta throughput de escritura; aparecen conflictos y control de flujo; latencia se dispara.
Causa raíz: Conflictos de certificación en filas calientes, demasiados escritores concurrentes o transacciones grandes causando sobrecarga de coordinación en todo el clúster.
Solución: Reducir contención de escritura (cambios de esquema, diseño de claves), dividir transacciones, fijar escrituras a un nodo (si es aceptable) o dejar de pretender que Galera es la bala de plata para escalar escrituras.
4) Hotspot en TiDB que nunca desaparece
Síntoma: Un nodo TiKV permanece caliente; PD “balancea” pero el dolor persiste; suben reintentos de transacción.
Causa raíz: Claves secuenciales o inserciones monotónicas creando hotspots de región; división de regiones insuficiente; sesgo de carga por tenant.
Solución: Cambiar diseño de claves (evitar PKs monotónicos en tablas calientes), habilitar/pre-splitting para tablas calientes, aislar tenants y usar programación de hotspots con cuidado.
5) Migración exitosa, pero aparecen bugs de corrección semanas después
Síntoma: Filas ocasionalmente faltantes/duplicadas, redondeos extraños, diferencias de sensibilidad a mayúsculas, o sorpresas de zona horaria.
Causa raíz: Diferencias en modo SQL, collation, conversiones implícitas o dependencia de la aplicación en comportamiento indefinido.
Solución: Bloquear modos SQL y collations, añadir chequeos de validación de datos y eliminar “magia de string-a-int” y ambigüedad de zona horaria en la aplicación.
6) El backup existe, la restauración falla
Síntoma: La restauración toma mucho más tiempo de lo planeado, o falla por permisos, binlogs faltantes o versiones incompatibles.
Causa raíz: Ruta de restauración no probada, snapshots inconsistentes o entorno de restauración subdimensionado.
Solución: Simulacros regulares de restauración, runbooks documentados y planificación de capacidad para throughput de restauración (red + disco + CPU).
Listas de verificación / plan paso a paso
Checklist de decisión: ¿deberías quedarte en MariaDB?
- Tu carga de escritura cabe en un primario con margen tras un tuning razonable.
- Puedes tolerar lag de réplicas o puedes aceptar los trade-offs de semi-sync.
- Tu dolor principal es calidad de consultas/índices, no el conteo de shards.
- Quieres el modelo de fallo más simple y la superficie operativa más pequeña.
Checklist de decisión: ¿deberías moverte a TiDB?
- Necesitas escalar escrituras más allá de un solo nodo sin shardear la aplicación.
- Puedes invertir en observabilidad: tracing, métricas por componente y gestión de capacidad.
- Puedes aceptar mayor latencia base a cambio de escala y HA.
- Estás dispuesto a rediseñar claves calientes y patrones de transacción.
Plan paso a paso de migración que sobrevive al contacto con producción
- Inventario de la carga: principales consultas por latencia y frecuencia, tablas top por escrituras, tablas más grandes por tamaño.
- Bloquear semánticas: modo SQL, zona horaria, collation, expectativas de aislamiento.
- Planificar índices primero: validar planes de consulta en el sistema objetivo para las top N consultas.
- Construir validación de datos: conteos, checksums por partición/rango e invariantes de negocio.
- Diseñar el cutover: dual-write vs CDC; definir rollback ante fallos.
- Practicar failover y restore: tanto en el sistema antiguo como en el nuevo antes del flip de producción.
- Hacer un dark launch: espejo de lecturas o tráfico shadow; comparar resultados y latencias.
- Aumentar gradualmente: 1% → 5% → 25% → 50% con criterios de aceptación explícitos.
- Congelar cambios riesgosos: nada de grandes refactors de esquema durante el ramp a menos que disfrutes del drama.
- Documentar la propiedad operativa: quién pagina por PD? quién pagina por compactaciones lentas? quién posee las puertas de esquema?
Checklist de runbook: cómo se ve “listo para prod”
- Job de backup ejecutándose con éxito monitoreado y tiempo de restauración conocido.
- Simulacro de restauración completado en los últimos 90 días con tiempos registrados.
- Dashboards por capa (SQL, almacenamiento, plano de control) con foco en p95/p99.
- Umbrales de alerta ligados al impacto usuario (latencia, tasa de errores), no a métricas de vanidad.
- Headroom de capacidad: disco, IO y CPU, más espacio para mantenimiento/compactación.
Preguntas frecuentes
1) ¿TiDB es un “reemplazo directo” de MariaDB/MySQL?
Para muchas apps, es lo suficientemente cercano para empezar a probar rápido. Pero “reemplazo directo” termina en rendimiento y comportamiento operativo. Trátalo como una reescritura de tus suposiciones.
2) ¿TiDB reemplaza la necesidad de réplicas de lectura?
Cambia el modelo. Escalas nodos SQL sin estado de TiDB para throughput de lectura, pero aún debes planificar dominios de fallo, colocación y vecinos ruidosos.
3) ¿Galera es una forma más simple de obtener lo que ofrece TiDB?
No. Galera puede ofrecer HA y algunas formas de escritura multi-nodo, pero no es lo mismo que una capa de almacenamiento distribuido con replicación Raft. Bajo contención de escritura pesada, el modelo de certificación de Galera puede perjudicar.
4) ¿Qué cargas hacen brillar a TiDB?
Necesidades altas de escalado de escrituras sin shardear la aplicación, datasets grandes con crecimiento horizontal y cargas mixtas donde escalar lecturas y escrituras independientemente ayuda. También: equipos que pueden operar sistemas distribuidos bien.
5) ¿Qué cargas deberían quedarse en MariaDB?
OLTP en una sola región con crecimiento predecible, requisitos de baja latencia y equipos que valoran simplicidad operativa sobre escalado horizontal de escrituras. MariaDB sigue siendo un caballo de batalla muy competente.
6) ¿Qué sorprende primero a los equipos que migran a TiDB?
Los hotspots. No porque no existieran antes, sino porque se manifiestan como “un líder de región se está derritiendo”, no solo “el primario está ocupado”.
7) ¿Cómo pienso en diferencias de coste?
MariaDB tiende a ser más barata para cargas moderadas porque compras menos nodos y menos red. TiDB suele costar más en infraestructura pero puede costar menos que el esfuerzo de ingeniería para shardear. El modelo correcto incluye carga de on-call y riesgo de migración, no solo conteo de nodos.
8) ¿Puedo migrar con casi cero tiempo de inactividad?
Sí, con patrones CDC/dual-write y un cutover cuidadoso. El riesgo de downtime rara vez es la copia; es la última milla: deriva de esquema, regresiones de plan y sorpresas operativas durante el ramp de tráfico.
9) ¿Cuál es la prueba pre-migración más valiosa?
Ejecutar las 50–200 consultas principales de producción en el sistema objetivo con una distribución de datos similar a producción, y comparar resultados de EXPLAIN ANALYZE. Las pruebas de corrección no atraparán desastres de plan.
10) ¿Cuál es el hábito operativo más valioso para cualquiera de los dos sistemas?
Simulacros de restauración. No opcionales. No “verificamos que el archivo exista”. Restauraciones reales con validación y pasos cronometrados.
Conclusión: próximos pasos que puedes ejecutar el lunes
Si estás eligiendo entre MariaDB y TiDB, decide en función de lo que estás dispuesto a operar. MariaDB premia la simplicidad disciplinada. TiDB premia a los equipos que tratan a los sistemas distribuidos como un trabajo de primera clase, no como un hobby accidental.
Haz esto a continuación:
- Extrae tus consultas principales y realiza comparaciones de planes (MariaDB
EXPLAIN, TiDBEXPLAIN ANALYZE). - Ejecuta la guía rápida de diagnóstico en tu endpoint p99 peor y clasifica el cuello de botella.
- Elige una estrategia de migración (CDC/dual-write) y escribe el plan de rollback antes de escribir el plan de cutover.
- Programa un simulacro de restauración. Ponlo en el calendario. Hazlo real.
No necesitas certeza perfecta. Necesitas riesgo controlado, rendimiento medido y un sistema que falle de maneras que ya hayas ensayado.