Tu sistema está tranquilo. Los gráficos son aburridos. Entonces marketing “lanza” algo, un socio vuelve a intentar requests con agresividad o algún cron decide que es hora de reindexar el universo. El tráfico de escrituras se dispara. La latencia lo sigue. De pronto estás aprendiendo qué hace realmente tu base de datos cuando se asusta.
Esto no es una guerra religiosa entre SQL y NoSQL. Es una guía de supervivencia para picos de escritura: qué hacen MariaDB (InnoDB) y MongoDB (WiredTiger) bajo presión, dónde fallan, cómo diagnosticar el cuello de botella rápido y qué cambios realmente mueven la aguja en producción.
Qué es realmente un pico de escritura (y por qué duele)
Un pico de escritura no es “alto QPS”. Es un desajuste entre la demanda de escrituras entrantes y el paso más lento y duradero en tu ruta de escritura. Ese paso puede ser la latencia de flush del disco, la serialización del log, la contención de locks, los acks de replicación o los checkpoints.
Bajo carga sostenida, tanto MariaDB como MongoDB pueden parecer heroicos. Bajo picos, la ilusión termina porque ambos motores eventualmente chocan contra un muro donde deben o bien:
- Aplicar retropresión (los clientes esperan; las colas crecen; la latencia en cola explota),
- Renunciar a la durabilidad (ack antes de persistir de forma segura),
- O desplomarse (OOM, disco lleno, espiral de lag de réplicas, agotamiento de hilos).
Cuando preguntas “quién sobrevive a los picos”, la pregunta real es: quién falla de forma predecible, y quién te da suficientes controles para fallar con seguridad—sin convertir el canal de incidentes en un pódcast en vivo.
Hechos interesantes y contexto histórico
- MariaDB se creó después de que Oracle adquiriera Sun (y por tanto MySQL), impulsada por preocupaciones de gobernanza y licencias más que solo por el rendimiento.
- MongoDB popularizó un modelo de documentos amigable para desarrolladores en un momento en que el sharding de bases relacionales todavía era mayormente “un proyecto de fin de semana y un arrepentimiento futuro”.
- InnoDB (el motor de almacenamiento por defecto en MariaDB) centra la durabilidad alrededor de un redo log y el flushing en background—las escrituras no son “solo escrituras”, son escrituras de log más posteriores flushes de páginas.
- WiredTiger de MongoDB usa un write-ahead log (journal) y checkpoints; el comportamiento en picos suele depender del ritmo de checkpoints y la presión de caché.
- Group commit mejoró dramáticamente a las bases transaccionales ante picos al agrupar el coste de fsync entre múltiples transacciones.
- Los write concerns de MongoDB (w:1, majority, journaling) son efectivamente un dial entre “rápido” y “probablemente durable”, y tu elección importa más durante picos.
- El lag de replicación no es solo “un problema de réplicas”; puede retroalimentar al primario cuando los clientes requieren acks de majority.
- La adopción de NVMe cambió la forma de los cuellos de botella: con dispositivos de alta IOPS, la CPU, la contención y la serialización del log pueden convertirse en el factor limitante antes.
- La red en la nube convirtió el “tiempo de reconocimiento de escritura” en un problema de sistemas distribuidos: las escrituras por majority pueden estar limitadas por la latencia del votante más lento, no por la CPU del primario.
MariaDB bajo picos: la realidad de InnoDB
La ruta de escritura que importa
Bajo InnoDB, una escritura transaccional típica implica:
- Modificar páginas en el buffer pool (memoria) y marcarlas como sucias.
- Añadir registros redo al buffer del redo log.
- En commit, asegurar que el redo sea durable según
innodb_flush_log_at_trx_commit. - Más tarde, flush de páginas sucias a los archivos de datos en background.
Durante picos, tres cosas dominan:
- Latencia de durabilidad del redo log (coste de fsync y serialización del log).
- Acumulación de páginas sucias (llenado del buffer pool y luego flushing forzado).
- Contención (locks de fila, mantenimiento de índices secundarios, páginas calientes y a veces locks de metadata).
Cómo “sobrevive” MariaDB a un pico
MariaDB suele sobrevivir a los picos si:
- Tu almacenamiento tiene latencia de fsync predecible (no solo altas IOPS).
- Tu redo log está dimensionado y configurado para evitar presión de flush constante.
- Evitas índices secundarios patológicos en tablas con muchas escrituras.
- Aceptas que la durabilidad estricta cuesta algo, y ajustas en torno a ello en lugar de fingir que es gratis.
El modo de fallo de MariaDB bajo picos suele ser una explosión de latencia, no un fallo inmediato—a menos que lo lleves a swap, llenes el disco o dejes que la replicación/manejo de conexiones se vaya de las manos.
Perillas de InnoDB que realmente importan durante picos
innodb_flush_log_at_trx_commit: 1 es lo más seguro; 2 es común para mejor rendimiento; 0 es “espero que la energía nunca falle”.sync_binlog: si usas binlog (replicación), esto es la otra mitad de la durabilidad. Ponerlo a 1 es seguro y puede ser costoso.innodb_log_file_sizeyinnodb_log_files_in_group: logs más grandes suavizan picos; demasiado pequeños fuerzan flushing agresivo.innodb_io_capacityyinnodb_io_capacity_max: si son demasiado bajos, las páginas sucias se acumulan; si son demasiado altos, puedes asfixiar la I/O de primer plano.innodb_buffer_pool_size: suficiente memoria evita que las lecturas compitan con las escrituras; demasiado puede ocultar problemas hasta que los checkpoints golpeen como un camión.innodb_flush_method=O_DIRECT: a menudo reduce el doble buffering en Linux.
Retropresión en MariaDB: mayormente implícita
MariaDB no te da un simple control de “profundidad de cola”. La retropresión aparece como:
- Incremento de latencia en commits (fsync del redo).
- Hilos esperando por locks o I/O.
- Réplicas quedando atrás (si las escrituras también producen binlog y las réplicas no pueden seguir el ritmo).
Cuando MariaDB entra en problemas, a menudo parece “la base de datos está arriba, pero nada termina”. Eso sigue siendo una forma de misericordia. Tu app puede agotar tiempo. Puedes reducir carga. Puedes hacer algo.
MongoDB bajo picos: la realidad de WiredTiger
La ruta de escritura que importa
El comportamiento de escritura de MongoDB depende mucho del write concern y del journaling, pero la ruta habitual es:
- La escritura entra en el primario y actualiza estructuras en memoria (caché de WiredTiger).
- Se añade al journal (write-ahead log); la durabilidad depende del journaling y de los intervalos de commit.
- La replicación envía operaciones a los secundarios vía el oplog; write concern majority espera a los votantes.
- Los checkpoints vuelcan periódicamente datos a disco, produciendo picos de I/O.
Cómo “sobrevive” MongoDB a un pico
MongoDB sobrevive a picos de escritura cuando:
- Tu disco puede absorber journaling + I/O de checkpoints sin picos largos de fsync.
- No estás tan al límite que la caché de WiredTiger esté constantemente expulsando páginas sucias.
- Tu topología de replicación puede mantener los acks de majority al día (o estás dispuesto a relajar el write concern durante picos).
- Tus documentos e índices están diseñados para localidad de escritura (o al menos no para sabotearla).
El modo de fallo más desagradable de MongoDB en picos es lag de replicación + write concern majority + disco lento. Esa combinación convierte un pico en una autoinfligida sincronización distribuida.
Perillas y comportamientos de WiredTiger que aparecen durante picos
- Write concern:
w:1vsmajority, yj:true. Este es tu tablero de conmutación entre latencia y durabilidad. - Checkpointing: los checkpoints crean picos periódicos de I/O; si el sistema ya está estresado, los checkpoints pueden amplificar el comportamiento de bloqueo.
- Presión de caché: cuando la caché está llena, la expulsión se vuelve el gobernador oculto del rendimiento de escrituras.
- Tamaño del oplog: demasiado pequeño y los secundarios se quedan fuera; demasiado grande y cambian los tiempos de recuperación, almacenamiento y perfil de I/O.
- Amplificación por índices: cada índice secundario es trabajo extra. MongoDB no está exento de la física.
Retropresión en MongoDB: más explícita, pero fácil de interpretar mal
MongoDB puede aplicar retropresión cuando no puede mantener el journaling/checkpointing o cuando la replicación no puede satisfacer el write concern lo suficientemente rápido. En la práctica verás:
- Colas en el driver y luego timeouts.
- Aumento de la actividad de “WT cache eviction”.
- Lag del oplog creciendo hasta que las elecciones, rollback o la obsolescencia de lecturas se conviertan en un problema de negocio.
La trampa: los equipos interpretan “MongoDB acepta escrituras rápido” como “MongoDB es durable rápido”. Bajo picos, esas son frases diferentes.
Quién “sobrevive” a los picos: una tabla de decisión defendible
Si necesitas garantías transaccionales estrictas bajo picos
Favorece MariaDB cuando necesitas integridad transaccional multi-fila, restricciones complejas y semánticas predecibles durante picos. El comportamiento de InnoDB es bien conocido: el coste del commit depende de la durabilidad del log y de la contención, no del misterio.
MongoDB puede ser durable y consistente, sí. Pero cuando requieres majority y journaling, has entrado en tierra de latencia distribuida. Bajo picos, esa tierra se vuelve cara rápidamente.
Si necesitas esquema flexible y puedes tolerar ajustar el write concern
Favorece MongoDB cuando el modelo de documentos es realmente tu modelo de datos (no “no queríamos diseñar tablas”), y puedes elegir explícitamente niveles de durabilidad durante picos.
La ventaja operativa de MongoDB: para ciertas cargas es más fácil hacer sharding horizontal y mantener las escrituras en flujo—siempre que seas disciplinado con las claves y los índices.
Si tus picos son “ingestión por ráfagas” y las lecturas son secundarias
Ambas pueden ingerir. La diferencia es dónde pagan:
- MariaDB paga en el commit (fsync de redo/binlog), y después vía flushing si sobrepasas los límites de páginas sucias.
- MongoDB paga via journaling y checkpoints, y potencialmente via lag de replicación cuando el write concern es estricto.
Si solo puedes permitirte una cosa confiable: latencia predecible
Aquí soy opinativo: elige el sistema cuyo modo de fallo puedas operacionalizar.
- MariaDB tiende a degradarse hacia “lento pero correcto” cuando está configurado sensatamente.
- MongoDB puede degradarse hacia “rápido pero no donde crees que está la verdad” si has sido casual con el write concern, la salud de la replicación o el disco.
Broma #1: Un pico de escritura es solo tus usuarios ejecutando una prueba de carga que no presupuestaste.
La cita que deberías pegar en el tablero
La esperanza no es una estrategia.
— General Gordon R. Sullivan
Esa frase sobrevive porque es lo más cierto que se ha dicho sobre escrituras en producción.
Guion rápido de diagnóstico
Tienes 10 minutos antes de que alguien sugiera “simplemente añade más pods”. Esto es lo que revisar primero, segundo, tercero—para que identifiques el cuello de botella real en vez de tratar síntomas.
Primero: ¿es latencia de flush del disco, o CPU/locks?
- Revisa la utilización del disco y await: si await es alto y la utilización está al máximo, estás limitado por I/O.
- Revisa steal y saturación de CPU: si la CPU está al máximo o estás siendo restringido, estás limitado por cómputo.
- Revisa esperas por locks: si los hilos esperan por locks, los gráficos de I/O pueden mentir.
Segundo: ¿la configuración de durabilidad está forzando sync en cada escritura?
- MariaDB:
innodb_flush_log_at_trx_commit,sync_binlog, formato de binlog, agrupación de commits. - MongoDB: write concern (w, j), comportamiento de intervalos de commit, esperas por majority.
Tercero: ¿es la replicación el limitador oculto?
- MariaDB: réplicas aplicando binlog despacio, configuraciones semi-sync o almacenamiento de red lento en réplicas.
- MongoDB: secundarios atrasados, elecciones, write concern majority esperando a un nodo enfermo.
Cuarto: ¿estás haciendo checkpoints/flushes demasiado agresivos (o demasiado tarde)?
- MariaDB: porcentaje de páginas sucias, presión de redo log, configuraciones de flushing en background.
- MongoDB: tasa de expulsión de la caché de WiredTiger, duración de checkpoints, presión del journal.
Quinto: ¿los índices y el esquema son el verdadero impuesto?
Los picos exponen la amplificación de escrituras. Un esquema que “iba bien” a 1k writes/s puede implosionar a 20k writes/s porque cada escritura toca demasiados índices, demasiadas claves calientes o demasiadas estructuras secundarias.
Tareas prácticas: comandos, salidas y qué decides
Estas son las tareas que realmente ejecuto cuando cae un pico. Cada una incluye el comando, salida de ejemplo, lo que significa y la decisión que tomas. Sin heroicidades, solo recetas.
1) Linux: confirma saturación y latencia del disco
cr0x@server:~$ iostat -x 1 5
Linux 6.5.0 (db01) 12/30/2025 _x86_64_ (8 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
12.10 0.00 6.20 18.40 0.00 63.30
Device r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
nvme0n1 110.0 4200.0 3.2 180.5 87.1 35.2 8.4 1.9 8.6 0.23 99.2
Qué significa: %util cerca de 100 y un alto avgqu-sz muestran una cola profunda. El await de escritura es ~8.6ms. Bajo picos, esto suele llegar a 20–100ms, y las bases de datos empiezan a hacer timeouts.
Decisión: Si el await sube con la carga, estás limitado por I/O. O reduces la frecuencia de fsync (con cuidado), agrupar commits, o pasas a almacenamiento más rápido/menos contendido.
2) Linux: revisa stalls de presión (CPU/memoria/I/O)
cr0x@server:~$ cat /proc/pressure/io
some avg10=12.45 avg60=8.21 avg300=2.14 total=9382211
full avg10=4.10 avg60=2.01 avg300=0.50 total=1923112
Qué significa: El kernel te dice que tareas se quedan bloqueadas esperando I/O. “full” indica períodos donde ninguna tarea podía progresar por I/O.
Decisión: Trátalo primero como un cuello de botella de plataforma. El tuning de la base de datos no superará un stack de almacenamiento saturado.
3) Linux: verifica espacio en sistema de archivos y cabeceras de inodos
cr0x@server:~$ df -h /var/lib/mysql /var/lib/mongodb
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p2 1.8T 1.6T 120G 94% /
/dev/nvme1n1p1 1.8T 1.2T 560G 69% /data
Qué significa: 94% usado coquetea con acantilados de rendimiento y errores operativos. Algunos sistemas de archivos se comportan mal cuando están casi llenos; las bases de datos se comportan mal cuando no pueden extender archivos.
Decisión: Si hay un pico de escritura en curso y estás por encima de ~90%, prioriza liberar espacio o añadir capacidad antes de perseguir planes de consulta.
4) MariaDB: mira qué cree el servidor que está pasando ahora
cr0x@server:~$ mysql -e "SHOW FULL PROCESSLIST\G" | head -n 40
*************************** 1. row ***************************
Id: 4312
User: app
Host: 10.10.2.14:51132
db: prod
Command: Query
Time: 12
State: Waiting for redo log flush
Info: COMMIT
*************************** 2. row ***************************
Id: 4321
User: app
Host: 10.10.2.18:51410
db: prod
Command: Query
Time: 8
State: Updating
Info: INSERT INTO events ...
Qué significa: “Waiting for redo log flush” es una señal luminosa: los commits están condicionados por la durabilidad del log. Ese es el clásico dolor de picos de escritura.
Decisión: Investiga latencia de fsync, dimensionamiento del redo log y ajustes de durabilidad. No empieces a añadir índices ahora mismo; te estás ahogando en el coste de flush.
5) MariaDB: confirma las configuraciones de durabilidad (las reales)
cr0x@server:~$ mysql -e "SHOW VARIABLES WHERE Variable_name IN ('innodb_flush_log_at_trx_commit','sync_binlog','binlog_format')"
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| binlog_format | ROW |
| innodb_flush_log_at_trx_commit| 1 |
| sync_binlog | 1 |
+-------------------------------+-------+
Qué significa: Esto es territorio de “seguridad máxima”: fsync del redo en cada commit, binlog fsync en cada commit. Bajo picos, eso puede convertirse en una hoguera de latencia de commits a menos que tu almacenamiento sea excelente.
Decisión: Si el negocio puede tolerar una pequeña ventana de pérdida ante un fallo de energía, considera innodb_flush_log_at_trx_commit=2 y/o sync_binlog=100 para ingestión con ráfagas—tras una revisión deliberada de riesgos.
6) MariaDB: inspecciona páginas sucias y presión de flushing de InnoDB
cr0x@server:~$ mysql -e "SHOW ENGINE INNODB STATUS\G" | egrep -i "Modified db pages|Log sequence number|Log flushed up to|pages flushed" -n | head
121:Log sequence number 98422341122
122:Log flushed up to 98422338816
401:Modified db pages 812345
405:Pages flushed up to 255112233
Qué significa: Un gran número de páginas modificadas indica acumulación de páginas sucias. Si “Log flushed up to” va por detrás del LSN durante un pico, los commits se encolan detrás del fsync.
Decisión: Si las páginas sucias se mantienen altas y el flushing no puede seguir, ajusta las configuraciones de capacidad de I/O y el tamaño del redo log. Si fsync es lento, arregla primero el almacenamiento.
7) MariaDB: detecta puntos calientes de contención de locks
cr0x@server:~$ mysql -e "SELECT * FROM information_schema.INNODB_LOCK_WAITS\G" | head -n 60
*************************** 1. row ***************************
requesting_trx_id: 123456789
requested_lock_id: 123456789:45:3:12
blocking_trx_id: 123456700
blocking_lock_id: 123456700:45:3:12
Qué significa: Transacciones están esperando a otras transacciones. Durante picos, una fila caliente o una página de índice caliente puede serializar el rendimiento.
Decisión: Si las esperas por locks se correlacionan con los picos, corrige los patrones de acceso (claves de partición, particionado, evita contadores calientes) en lugar de tunear fsync.
8) MariaDB: verifica la tasa de aciertos del buffer pool y la contención lectura/escritura
cr0x@server:~$ mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%'; SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';"
+---------------------------------------+-----------+
| Variable_name | Value |
+---------------------------------------+-----------+
| Innodb_buffer_pool_read_requests | 982341122 |
| Innodb_buffer_pool_reads | 8123411 |
+---------------------------------------+-----------+
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| Innodb_buffer_pool_pages_dirty | 81234 |
+--------------------------------+-------+
Qué significa: Si las lecturas físicas suben durante un pico de escrituras, tu buffer pool puede ser demasiado pequeño o estás thrashing. Las páginas sucias también importan: demasiadas desencadenan tormentas de flushing.
Decisión: Si las lecturas suben con las escrituras, añade memoria o reduce la presión de lectura (cache, cambios en consultas). Si las páginas sucias son altas, ajusta el flushing y el tamaño de los logs.
9) MongoDB: revisa la salud del replica set y el lag
cr0x@server:~$ mongosh --quiet --eval 'rs.status().members.map(m=>({name:m.name,state:m.stateStr,health:m.health,lagSeconds:(m.optimeDate?Math.round((new Date()-m.optimeDate)/1000):null)}))'
[
{ name: 'mongo01:27017', state: 'PRIMARY', health: 1, lagSeconds: 0 },
{ name: 'mongo02:27017', state: 'SECONDARY', health: 1, lagSeconds: 6 },
{ name: 'mongo03:27017', state: 'SECONDARY', health: 1, lagSeconds: 84 }
]
Qué significa: Un secundario está 84 segundos atrasado. Si los clientes usan w:"majority", ese lag puede añadir latencia directa (o timeouts) según los requisitos de votación y write concern.
Decisión: Si se requieren acks de majority, arregla el nodo atrasado (disco, CPU, red) o quítalo temporalmente de los votantes, con control de cambios.
10) MongoDB: confirma el write concern que usa la aplicación
cr0x@server:~$ mongosh --quiet --eval 'db.getMongo().getWriteConcern()'
{ w: 'majority', wtimeout: 0 }
Qué significa: Writes con majority. Excelente para corrección; bajo picos, ahora dependes de la salud de la replicación y la latencia entre nodos.
Decisión: Durante ingestas planificadas, considera un write concern distinto solo si los datos pueden reconstruirse y el riesgo está documentado. Si no, escala el replica set y el almacenamiento para cumplir el requisito.
11) MongoDB: revisa la presión de caché WiredTiger y la tasa de expulsión
cr0x@server:~$ mongosh --quiet --eval 'var s=db.serverStatus().wiredTiger.cache; ({ "bytes currently in cache": s["bytes currently in the cache"], "tracked dirty bytes": s["tracked dirty bytes in the cache"], "pages evicted": s["pages evicted"] })'
{
"bytes currently in cache": 29192355840,
"tracked dirty bytes": 9423123456,
"pages evicted": 182341122
}
Qué significa: Bytes sucios altos y expulsiones rápidas a menudo significan que el motor está gastando ciclos en sacar datos sucios, lo que puede estrangular las escrituras y amplificar los bloqueos de checkpoints.
Decisión: Si la expulsión es intensa durante picos, revisa el dimensionamiento de la caché, el tamaño de documentos/índices y el rendimiento de disco. No “simplemente añadas RAM” sin comprobar el comportamiento de checkpoints.
12) MongoDB: inspecciona operaciones actuales por síntomas de lock/I/O
cr0x@server:~$ mongosh --quiet --eval 'db.currentOp({active:true,secs_running:{$gte:2}}).inprog.slice(0,3).map(o=>({opid:o.opid,secs:o.secs_running,ns:o.ns,desc:o.desc,waitingForLock:o.waitingForLock,locks:o.locks}))'
[
{
opid: 18231,
secs: 9,
ns: 'prod.events',
desc: 'conn31291',
waitingForLock: false,
locks: { Global: 'w' }
},
{
opid: 18247,
secs: 5,
ns: 'prod.events',
desc: 'conn31340',
waitingForLock: false,
locks: { Global: 'w' }
}
]
Qué significa: Escrituras de larga duración pueden indicar stalls de I/O aguas abajo, contención de índices o presión de journaling. MongoDB moderno tiene locking fino, pero la presencia de locks globales aún puede mostrarse en agregados.
Decisión: Si las operaciones duran mucho sin esperas por locks, sospecha latencia de almacenamiento o problemas de checkpoint/journal. Correlaciona con métricas de disco.
13) Linux: confirma que no estás siendo limitado por cgroups
cr0x@server:~$ systemctl show mariadb -p CPUQuota -p MemoryMax
CPUQuota=50%
MemoryMax=8589934592
Qué significa: Le diste a la base de datos la mitad de una CPU y 8GB de RAM y esperaste que tragara picos. Audaz.
Decisión: Elimina throttles artificiales para servicios stateful, o diseña explícitamente para ellos con control de admisión y encolado.
14) Linux: revisa actividad de swap (el asesino silencioso)
cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
4 2 524288 112340 8204 3124000 40 120 210 1820 980 2200 22 7 48 23 0
Qué significa: Swap in/out durante picos convierte “almacenamiento rápido” en “miseria lenta”. Las latencias de la base de datos se vuelven no acotadas.
Decisión: Reduce la presión de memoria (buffers, tamaño de caché), arregla cargas co-localizadas o mueve la base de datos a un host que no trate la RAM como opcional.
Tres mini-historias corporativas (cómo esto falla en la vida real)
Mini-historia #1: El incidente causado por una suposición errónea
Una compañía SaaS mediana usaba MongoDB para ingestión de eventos. El modelo de datos tenía sentido: los eventos eran documentos, el esquema evolucionaba semanalmente y el sharding estaba en la hoja de ruta. Tenían un replica set de tres miembros en distintas zonas y se sentían bastante maduros al respecto.
Entonces un sistema asociado empezó a reintentar ante 500s sin jitter. Las escrituras se dispararon y la CPU del primario se mantuvo razonable. El equipo asumió “MongoDB aguanta altos volúmenes de escritura”, porque había ido bien antes. La latencia subió de todos modos, y luego la app empezó a agotar tiempo en escrituras con w:"majority". El responsable del incidente miró los gráficos de disco del primario y vio algo que parecía solo “ocupado”, no catastrófico.
La suposición errónea fue sutil: pensaban que el write concern majority significaba “dos de tres, siempre rápido”. En realidad, un secundario había estado degradado durante semanas—lo bastante sano para votar, lo bastante enfermo para quedarse muy atrás. Bajo el pico, se atrasó aún más. Los acks de majority ahora dependían del votante más lento poniéndose al día con suficiente frecuencia para confirmar nuevas operaciones.
Se estabilizaron haciendo step down del secundario degradado (y luego lo volvieron a añadir tras repararlo), reduciendo efectivamente el quorum de acks. La solución a largo plazo fue operativa: monitorizar el lag de replicación con alertas que disparen antes de que sea crisis, y no permitir que un votante enfermo permanezca en el quorum por conveniencia.
No “escalaron” el incidente. Eliminó la suposición de que la salud de la topología es opcional durante picos. No lo es.
Mini-historia #2: La optimización que salió mal
Una plataforma de e‑commerce usaba MariaDB para pedidos e inventario. Esperaban escrituras en ráfagas durante lanzamientos, así que ajustaron para velocidad: buffer pool más grande, configuración agresiva de hilos y pusieron innodb_flush_log_at_trx_commit=2 para reducir la presión de fsync. Funcionó. La latencia de commits bajó. Todos celebraron.
Luego el contragolpe: el mismo equipo aumentó la concurrencia en la app para “usar la nueva holgura” y añadieron algunos índices secundarios para soportar nuevos dashboards. Durante el siguiente pico, las transacciones se apilaron detrás de locks de fila en filas de inventario y en páginas calientes de índices secundarios. Al mismo tiempo, las páginas sucias se acumularon rápido. Cuando el sistema tuvo que flushar agresivamente, el I/O se disparó, la latencia se volvió no lineal y los reintentos de la app lo convirtieron en una tormenta.
La optimización no estaba mal por sí misma. El error fue pensar que un solo ajuste es una mejora de capacidad. Al abaratar commits, animaron más escrituras concurrentes sobre los mismos puntos calientes, amplificando la contención y la presión de flushing en background.
La solución fue ingeniería aburrida: quitar un índice de dashboard que castigaba la ruta de escritura, shardear las actualizaciones más calientes de inventario añadiendo una estrategia de particionado y aplicar limitación de velocidad del lado cliente para que los reintentos no se conviertan en carga. Solo entonces su ajuste de durabilidad produjo ganancias estables.
Mini-historia #3: La práctica aburrida pero correcta que salvó el día
Una compañía tipo fintech (la que dice “fintech” pero vende suscripciones) usaba ambos: MariaDB para transacciones y MongoDB para eventos de auditoría. Vivían en un mundo de revisiones de cumplimiento y preguntas incómodas, así que eran alérgicos a “simplemente ponerlo a 0”.
También hacían algo poco sexy: corrían un “ensayo de picos” mensual. No un benchmark sintético en laboratorio—un aumento controlado de carga en staging con volúmenes de datos parecidos a producción y la misma clase de almacenamiento. Practicaban fallos: lag de réplicas, inyección de latencia de disco, failover primario. Alguien siempre se quejaba de que tomaba tiempo. Alguien siempre encontraba algo importante.
Un mes, el ensayo reveló que un nuevo secundario de MongoDB en otra zona tenía peor latencia de fsync. Las escrituras majority parecían bien en tráfico normal y fueron un problema solo cuando la tasa de escritura se duplicó. Lo arreglaron antes de la campaña real moviendo el nodo a un tier de almacenamiento mejor y ajustando la votación para que el miembro lento no dictara la latencia de acks.
Durante el pico real semanas después, ambas bases estuvieron muy cargadas pero estables. El equipo no pareció brillante. Pareció aburrido. Ese es el punto.
Errores comunes: síntoma → causa raíz → solución
1) Síntoma: commits se estancan, muchos hilos “Waiting for redo log flush” (MariaDB)
Causa raíz: latencia de fsync o serialización del redo log se vuelve el gobernador; log demasiado pequeño aumenta la presión.
Solución: Mover a almacenamiento de menor latencia; aumentar tamaño del redo log; validar innodb_flush_log_at_trx_commit y sync_binlog según necesidades de durabilidad del negocio; asegurar que binlog y redo estén en almacenamiento sensato.
2) Síntoma: picos de latencia de escritura repentinos cada pocos minutos (MongoDB)
Causa raíz: ciclos de checkpoint/journal que causan picos periódicos de I/O; agravado por presión de caché.
Solución: Asegurar throughput de disco y baja latencia en cola; reducir amplificación de escritura (índices, tamaño de documento); asegurar que WiredTiger no esté privando al page cache del SO; revisar comportamiento de checkpoints en métricas.
3) Síntoma: escrituras en MongoDB hacen timeout solo con majority
Causa raíz: un secundario votante está atrasado o lento; el majority ack ahora incluye una ruta lenta.
Solución: reparar/reemplazar el secundario lento; considerar ajustar miembros votantes; arreglar consistencia de red y almacenamiento entre nodos; aumentar el oplog si los secundarios se descuelgan.
4) Síntoma: CPU de MariaDB está bien, pero el QPS se colapsa
Causa raíz: contención de locks (filas calientes, gap locks, transacciones largas) o espera de I/O; los gráficos de CPU son engañosos.
Solución: identificar esperas por locks; reducir el alcance de transacciones; evitar contadores calientes; cambiar el patrón de acceso o la aislación; añadir índices apropiados solo si reducen el tiempo de lock (no solo “para lecturas”).
5) Síntoma: ambas bases “aleatoriamente” se ponen lentas durante picos en VMs
Causa raíz: vecinos ruidosos y contención de almacenamiento; latencia variable de fsync; steal de CPU.
Solución: aislar almacenamiento; volúmenes dedicados; medir la cola de fsync; comprobar CPU steal; dejar de colocalizar trabajos batch con la base de datos.
6) Síntoma: un pico de escritura causa una tormenta de reintentos y luego todo muere
Causa raíz: reintentos de cliente sin backoff; la base de datos se convierte en el limitador de tasa; los timeouts amplifican la carga.
Solución: backoff exponencial con jitter; circuit breakers; control de admisión en servidor; limitar concurrencia; devolver 429/503 intencionalmente en lugar de dejar que los timeouts causen una cascada.
7) Síntoma: “Escalamos IOPS de disco pero sigue lento”
Causa raíz: estás limitado por serialización (mutex de log, shard caliente), CPU o latencia de replicación en red, no por IOPS brutas.
Solución: medir dónde se gasta el tiempo (fsync, locks, acks de replicación); reducir puntos calientes; shardear/particionar para distribuir escrituras; verificar que obtuviste menor latencia en cola, no solo mayor rendimiento pico.
Listas de verificación / plan paso a paso
Paso a paso: preparar MariaDB para picos de escritura predecibles
- Mide la cola de latencia de fsync en la clase de volumen real usada para redo/binlog. Si p99 es malo, para y arregla el almacenamiento primero.
- Define la durabilidad intencionalmente: decide
innodb_flush_log_at_trx_commitysync_binlogcon una declaración de riesgos por escrito. - Dimensiona correctamente los redo logs para suavizar picos y reducir la presión de flush.
- Audita índices secundarios en tablas con muchas escrituras. Elimina índices por vanidad. Mantén los que evitan full scans que bloquean demasiado.
- Controla el tamaño de las transacciones: commits pequeños son más fáciles de agrupar y replicar; transacciones enormes crean tormentas de lock y flush.
- Planifica la retropresión: establece timeouts sensatos, limita la concurrencia de la app, implementa reintentos con jitter.
- Ensayo de replicación: confirma que las réplicas pueden aplicar a la tasa de pico; si no, las réplicas serán tu problema en tiempo de recuperación.
Paso a paso: preparar MongoDB para picos de escritura predecibles
- Define write concern por carga de trabajo (no por humor). Escrituras críticas: majority+journal. Telemetría reconstruible: quizá menor, con guardrails.
- Monitoriza el lag de replicación y las elecciones como si fuera un SLO de primera clase. Bajo picos, lo es.
- Valida el almacenamiento para journaling y checkpoints: baja latencia en cola gana sobre IOPS de titularidad.
- Elige claves de shard para distribuir escrituras si shardeas. Shards calientes convierten “distribuido” en “dolor de un solo nodo con pasos extra”.
- Disciplina de índices: cada índice es un impuesto sobre tu presupuesto de escritura. Mantén los que sirven consultas reales.
- Capacidad para caché + expulsiones: vigila bytes sucios y churn de expulsión; evita operar constantemente al límite.
- Timeouts y políticas de reintento del driver: configúralos conscientemente; no dejes que el driver “te ayude” a provocar una tormenta de reintentos.
Broma #2: Las bases de datos no “manejan picos”. Negocian con ellos, y el contrato está escrito en milisegundos.
Preguntas frecuentes
1) ¿Cuál es más rápida en escrituras: MariaDB o MongoDB?
Ninguna “gana” de forma universal. MongoDB puede ingerir rápido con write concern relajado y una buena clave de shard. MariaDB puede ingerir rápido con group commit y índices sensatos. Bajo durabilidad estricta, ambos están limitados por la latencia de fsync en cola y por la amplificación de escrituras.
2) ¿Cuál es la razón más común por la que MariaDB se derrite durante picos de escritura?
El coste de la durabilidad en commits (fsync de redo/binlog) más la presión de flushing por páginas sucias, a menudo agravado por demasiados índices secundarios o contención en filas calientes.
3) ¿Cuál es la razón más común por la que MongoDB se derrite durante picos de escritura?
Lag de replicación más write concern majority, o picos de I/O por checkpoint/journal cuando el disco no mantiene baja la latencia en cola.
4) ¿Puedo “simplemente escalar horizontalmente” para sobrevivir a picos?
A veces. El sharding de MongoDB puede repartir escrituras si eliges una clave que distribuya. MariaDB puede escalar con sharding en la capa de aplicación o con soluciones de clustering, pero los entornos multi-writer tienen sus propias limitaciones. Escalar horizontalmente es un proyecto de diseño, no un botón.
5) ¿Es aceptable apagar la durabilidad para picos?
Solo si los datos son reconstruibles y tienes un procedimiento documentado y ensayado. De lo contrario estás intercambiando un incidente ahora por uno de integridad de datos después, lo cual suele ser más caro y menos perdonable.
6) ¿Debería poner redo logs / journal en discos separados?
La separación puede ayudar si la contención es el problema y tienes aislamiento real (no dos particiones en el mismo dispositivo subyacente). A menudo la mejor victoria es menos dispositivos, más rápidos y más predecibles que diseños complicados.
7) ¿Cuál es la métrica única mejor para sobrevivir picos?
La latencia cola de escrituras durables. No la media. No el rendimiento pico. Si la p99 de commit/journal empeora, todo lo upstream empezará a comportarse mal también.
8) ¿Más RAM arregla los problemas de picos de escritura?
A veces los retrasa. Para MariaDB, más buffer pool reduce contención de lecturas y puede suavizar escrituras, pero también permite que se acumulen más páginas sucias. Para MongoDB, más caché reduce churn, pero los checkpoints y journaling siguen golpeando el disco. La RAM ayuda; no revoca la física.
9) ¿Qué hay de Galera (MariaDB) vs replica sets de MongoDB para picos?
Los sistemas multi‑master más o menos síncronos pueden reducir algo del dolor del failover pero también pueden amplificar la latencia de escritura porque la coordinación forma parte de cada commit. Bajo picos, la sobrecarga de coordinación no es tu amiga salvo que esté cuidadosamente diseñada.
10) ¿Cómo elijo si mi carga es “requisitos futuros desconocidos”?
Si necesitas constraints relacionales y transacciones complejas, empieza con MariaDB y añade un store de documentos donde encaje. Si tu dominio es verdaderamente centrado en documentos y estás comprometido con el diseño de shards y la disciplina de write concern, MongoDB puede ser la forma operacional más simple.
Conclusión: próximos pasos que puedes ejecutar
Los picos de escritura no premian el optimismo. Premian sistemas con latencia de escritura durable predecible, diseño disciplinado de esquema/índices y retropresión que no se convierta en huracán de reintentos.
- Elige tu postura de durabilidad (ajustes de commit en MariaDB / write concern en MongoDB) y déjala por escrito como política.
- Mide la cola de fsync/journal en tu almacenamiento real. Si es inconsistente, arregla la plataforma antes de tocar planes de consulta.
- Haz un ensayo de picos mensual: lag de replicación, checkpoints, failovers y comportamiento de reintentos de clientes.
- Implementa shedding de carga: limita la concurrencia, añade reintentos con jitter y deja de fingir que los timeouts son una estrategia.
- Reduce la amplificación de escritura: audita índices, evita claves calientes y mantiene transacciones pequeñas y aburridas.
Si quieres una única lección: MariaDB tiende a fallar despacio y en voz alta; MongoDB tiende a fallar de maneras dependientes de la topología. Diseña para el modo de fallo que puedas gestionar a las 2 a.m., no para el benchmark que presumes a las 2 p.m.