La velocidad de restauración es donde la teoría de bases de datos se encuentra con la fea realidad de la latencia de almacenamiento, la contención de CPU y el pánico de “espera, ¿cuál backup es el correcto?”. Tu RTO no es un número de hoja de cálculo. Es el tiempo entre la primera alerta y el momento en que tu aplicación deja de comportarse como una máquina expendedora embrujada.
Si necesitas un RTO inferior a 15 minutos, no “optimizas restauraciones”. Diseñas todo el camino de backup+recuperación como un sistema de producción: predecible, medible, ensayado y brutalmente aburrido.
Qué significa realmente “RTO inferior a 15 minutos”
El RTO es el tiempo para restaurar el servicio, no el tiempo para “terminar la restauración”. Si tu servicio necesita la base de datos y tu base de datos necesita connection pooling, DNS, secretos y compatibilidad de esquema, todo eso está dentro del alcance. Una restauración de base de datos de 9 minutos es un apagón de 30 minutos si todavía tienes:
- Un catch-up de 12 minutos de WAL/binlog porque olvidaste que estás haciendo PITR.
- Un calentamiento de caché de 6 minutos porque tu app “descubre” el rendimiento otra vez desde frío.
- Un retraso humano de 10 minutos porque los pasos de restauración viven en la cabeza de alguien.
Para un RTO por debajo de 15 minutos, asume que no tienes tiempo para pensar. Debes poder ejecutar un árbol de decisiones predefinido, con capacidad preprovisionada, y debes saber (no esperar) que el backup es válido.
Las matemáticas incómodas
15 minutos son 900 segundos. Si tu directorio de datos físico tiene 800 GB, no lo vas a restaurar desde un almacenamiento de objetos a 200 MB/s. No a menos que la física también esté en rotación de on-call.
Así que alcanzar 15 minutos generalmente significa una de estas arquitecturas:
- Hot standby / promoción de réplica (restauración = promover + redirigir).
- Rollback desde snapshot (restauración de snapshot ZFS/LVM/EBS y adjuntar).
- Restauración física a nodos pre-calentados (la transferencia de datos es local o ya está preparada).
- Dataset lo suficientemente pequeño como para que una restauración verdadera quepa en la ventana (raro en sistemas maduros).
Los dumps lógicos para sistemas grandes son para migraciones y arqueología. No son tu plan de RTO de 15 minutos.
Caminos de restauración: MariaDB vs PostgreSQL (qué es rápido y qué no)
La restauración más rápida suele ser “no restaurar”
Para MariaDB y PostgreSQL, la recuperación más rápida es la promoción de una réplica que ya esté al día. Si puedes cumplir tu RPO con replicación asíncrona, perfecto. Si no puedes, paga por replicación síncrona o acepta un radio de impacto mayor.
Físico vs lógico: la bifurcación
Restauración lógica (mysqldump/mariadb-dump, pg_dump) es lenta porque vuelve a ejecutar SQL, reconstruye índices y obliga a la base de datos a hacer mucho trabajo de CPU que ya se había hecho una vez. También suele tener cuellos de botella single-thread en los lugares equivocados.
Restauración física (MariaDB: Mariabackup; PostgreSQL: pgBackRest, pg_basebackup, restauración a nivel de archivos) es rápida porque mayormente copias archivos y luego haces el replay de recuperación.
Perfil de velocidad de restauración de MariaDB
- Ruta rápida: backup físico con Mariabackup, preparado con antelación, copy-back en almacenamiento rápido y luego InnoDB crash recovery / aplicación de redo al arrancar.
- Dónde duele: la fase de prepare (si se difiere), el I/O de copy-back y la recuperación de InnoDB si los logs son enormes o el comportamiento de fsync es conservador.
- PITR: aplicar binary logs (binlog) después de restaurar el backup base. Eso puede ser rápido o dolorosamente serial dependiendo del volumen de escrituras y las limitaciones de apply single-thread en tu configuración.
Perfil de velocidad de restauración de PostgreSQL
- Ruta rápida: restaurar backup físico (pgBackRest restore o basebackup), arrancar instancia, replay de WAL hasta consistencia o hasta un target (PITR), promover.
- Dónde duele: la velocidad de replay de WAL (I/O y CPU), el throughput del comando de restore (fetch de segmentos WAL) y la configuración de checkpoint/redo.
- PITR: puede ser muy rápido si el WAL archive es local y paralelizado; puede ser miserable si el WAL está remoto y serializado o si el objetivo de recuperación está muy atrasado.
Consejo con opinión: si necesitas RTO inferior a 15 minutos, diseña para promoción o rollback por snapshot. Si cumplimiento exige “restaurar desde backup”, al menos usa backups físicos y colócalos en el almacenamiento destino antes de necesitarlos.
Hechos e historia que importan en la velocidad de restauración
- El WAL de PostgreSQL ha sido central desde los 90; la seguridad ante crashes y PITR se incorporaron temprano a la arquitectura, y la recuperación es fundamentalmente “reproducir logs hasta alcanzar consistencia”.
- InnoDB se convirtió en el motor por defecto de MySQL en 5.5, y MariaDB heredó esa línea. La velocidad de restauración depende en gran medida de “qué tan rápido InnoDB puede volverse consistente de nuevo”.
- pg_dump es deliberadamente lógico y portable; es excelente para migraciones y saltos de versión, y terrible para RTO estrictos a escala.
- Mariabackup es un fork de Percona XtraBackup, construido para backups físicos en caliente sin detener escrituras. La fase de “prepare” existe porque necesita dejar el backup consistente.
- Los replication slots de PostgreSQL previenen la eliminación de WAL mientras un consumidor lo necesita; genial para durabilidad, terrible si olvidas un slot abandonado y tu disco se llena durante una crisis.
- La replicación MySQL/MariaDB históricamente tuvo dificultades con el apply paralelo en ciertas cargas; las mejoras modernas ayudan, pero la velocidad de apply de binlog sigue siendo un spoiler común del RTO.
- Los sistemas de archivos copy-on-write (ZFS, btrfs) cambiaron las reglas para rollbacks rápidos desde snapshot—cuando se usan correctamente. Cuando se usan mal, también inventaron nuevas formas de saturar IOPS.
- PostgreSQL 9.6 mejoró el replay de WAL y el comportamiento de vacuum de maneras que indirectamente ayudan a los tiempos de recuperación bajo cargas intensas de escritura (menos bloat, menos churn, mejor comportamiento en background tras la restauración).
- MariaDB y PostgreSQL dependen de las semánticas de fsync; tu velocidad de restauración puede estar dominada por las garantías de durabilidad del almacenamiento más que por el código del motor.
Los cuellos de botella en la restauración que no desaparecen por arte de magia
1) Mover bytes: ancho de banda e IOPS
La restauración física es un problema de copia de archivos más replay de recuperación. Si tus datos están en HDD o en almacenamiento de red con latencia impredecible, tu RTO es básicamente un pronóstico meteorológico.
Para menos de 15 minutos, quieres:
- SSD/NVMe para el volumen de la base de datos.
- Preparación local del backup base más reciente.
- Throughput secuencial predecible y suficientes IOPS aleatorias para WAL/redo apply.
2) Replay de recuperación: comportamiento de WAL vs redo log
La recuperación de PostgreSQL reproduce WAL. MariaDB/InnoDB reproduce redo y aplica cambios a páginas de datos. Ambos son sensibles a:
- Cuántas páginas sucias deben reconciliarse.
- Frecuencia de checkpoints y tamaño de los buffers de log.
- Tasa de fsync y amplificación de escritura.
3) CPU y elecciones de compresión
La compresión es una trampa clásica: ayuda la red y el almacenamiento, y luego asesina silenciosamente la CPU durante la recuperación. Si comprimes los backups agresivamente, debes asegurar que los hosts de restauración tengan margen de CPU y que puedas paralelizar la descompresión.
Broma #1: La compresión es como una membresía de gimnasio—comprarla se siente productivo, usarla durante una emergencia se siente personal.
4) “Restaurado” no significa “usable”
Aun después de que la base de datos arranque, puede que sigas sin servicio:
- PostgreSQL: larga recuperación por crash o replay; luego tormentas de autovacuum; luego caché fría.
- MariaDB: el buffer pool de InnoDB está frío; el adaptive hash index se calienta; la replicación se reconstruye; las consultas hacen timeouts por inestabilidad de planes.
5) Metadatos: privilegios, extensiones y drift
Las restauraciones lógicas fallan ruidosamente cuando faltan extensiones o roles. Las restauraciones físicas fallan silenciosamente cuando tu configuración diverge, tu instancia arranca con ajustes distintos y tu aplicación percibe cambios de comportamiento bajo carga.
Una idea parafraseada de Werner Vogels (CTO de Amazon): Diseña sistemas asumiendo que fallarán; la fiabilidad viene de la preparación y la automatización, no de la esperanza.
Playbook de diagnóstico rápido
Esta es la secuencia on-call cuando el tiempo de restauración se dispara y necesitas encontrar el cuello de botella en minutos, no en un postmortem.
Primero: ¿estás restaurando bytes o reponiendo logs?
- Si aún estás copiando archivos: tienes un problema en la ruta de ancho de banda/I/O.
- Si la BD está “arrancando” pero no “lista”: tienes un problema de replay de recuperación o checkpointing.
- Si está “lista” pero la app está caída: tienes un problema de conectividad, credenciales o calentamiento.
Segundo: revisa la latencia del almacenamiento, no el throughput
Las restauraciones a menudo hacen ráfagas de escrituras pequeñas. La latencia te mata primero. Puedes tener un número enorme de MB/s y aun así perder minutos en fsync.
Tercero: verifica si PITR es el sumidero de tiempo
PITR es innegociable para algunas organizaciones. Bien. Pero debe ser diseñado: WAL/binlog archivados localmente, fetch paralelo y una decisión probada de “hasta qué punto retrocedemos”.
Cuarto: confirma que no te estás saboteando con la configuración
Durante restore/recovery, algunas configuraciones deberían ser temporalmente más agresivas y luego revertidas. Si nunca planificaste eso, estás atascado con valores por defecto que optimizan seguridad sobre velocidad (lo cual es razonable, pero no cumple tu RTO).
Quinto: valida la integridad del backup temprano
Si tu backup está corrupto, cada minuto que pases “afinando” es un minuto que no te estás cambiando a una réplica o snapshot. Valida rápido, cambia de estrategia rápido.
Tareas prácticas: comandos, salidas, decisiones
Estas tareas están pensadas para ejecutarse durante la planificación y durante un incidente. Cada una incluye: comando, qué significa la salida y qué decisión tomar a continuación. Úsalas como columna vertebral del runbook.
Tarea 1: Medir throughput bruto de disco (secuencial) en el destino de restauración
cr0x@server:~$ sudo fio --name=seqread --filename=/var/lib/postgresql/fio.test --size=4G --bs=1M --iodepth=16 --rw=read --direct=1 --numjobs=1
seqread: (groupid=0, jobs=1): err= 0: pid=22341: Thu Dec 31 10:11:12 2025
read: IOPS=1650, BW=1650MiB/s (1730MB/s)(4096MiB/2481msec)
Significado: Un BW alto indica que la copia secuencial no será tu cuello de botella. Si ves <300 MiB/s en expectativas de SSD/NVMe, estás en la clase de almacenamiento equivocada o lo estás compartiendo mal.
Decisión: Si el BW es bajo, deja de planear “restaurar desde cero”. Planea promoción de réplica o restauración basada en snapshot.
Tarea 2: Medir latencia fsync-intensiva (escritura aleatoria) en el destino de restauración
cr0x@server:~$ sudo fio --name=randwrite --filename=/var/lib/mysql/fio.test --size=2G --bs=4k --iodepth=64 --rw=randwrite --direct=1 --numjobs=4 --time_based --runtime=30
randwrite: (groupid=0, jobs=4): err= 0: pid=22410: Thu Dec 31 10:12:02 2025
write: IOPS=42000, BW=164MiB/s (172MB/s), lat (usec): avg=610, max=22000
Significado: Latencia media en cientos de microsegundos es decente. Milisegundos bajo carga estirarán la recuperación por crash y el replay de WAL.
Decisión: Si la latencia es mala, reduce la presión concurrente de recuperación (throttle de jobs), mueve WAL/binlog a un volumen más rápido o falla a un nodo con mejor almacenamiento.
Tarea 3: Comprobar el estado de recuperación y el progreso de replay en PostgreSQL
cr0x@server:~$ sudo -u postgres psql -c "select pg_is_in_recovery(), now() as ts, pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn();"
pg_is_in_recovery | ts | pg_last_wal_receive_lsn | pg_last_wal_replay_lsn
-------------------+-------------------------------+-------------------------+------------------------
t | 2025-12-31 10:13:11.552781+00 | 4A/9B2C1F20 | 4A/9B29A4D8
(1 row)
Significado: Receive LSN por delante de replay LSN significa que el replay está atrasado (limitado por CPU/I/O). Si receive LSN es NULL, no estás recibiendo WAL (problema de archive/stream).
Decisión: Si el replay va muy atrasado, revisa latencia de disco y ajustes de recovery; si no recibes WAL, arregla la recuperación del archive o la conectividad de replicación.
Tarea 4: Inspeccionar logs de PostgreSQL en busca de cuellos de botella en recuperación
cr0x@server:~$ sudo tail -n 30 /var/log/postgresql/postgresql-16-main.log
2025-12-31 10:12:58.123 UTC [21011] LOG: starting PostgreSQL 16.2 on x86_64-pc-linux-gnu
2025-12-31 10:12:58.456 UTC [21011] LOG: entering standby mode
2025-12-31 10:13:05.990 UTC [21011] LOG: redo starts at 4A/9A000028
2025-12-31 10:13:11.770 UTC [21011] LOG: consistent recovery state reached at 4A/9B0000A0
2025-12-31 10:13:11.771 UTC [21011] LOG: restored log file "000000010000004A0000009B" from archive
Significado: “restored log file … from archive” repitiéndose lentamente sugiere que el fetch del archive es el cuello de botella (red, latencia de object store). Si redo inicia y luego se queda con checkpoints, el almacenamiento está sufriendo.
Decisión: Si el fetch del archive es lento, prepara WAL localmente o habilita recuperación WAL paralela vía tu herramienta de backup.
Tarea 5: Comprobar estado de restore de pgBackRest y salud del archive WAL
cr0x@server:~$ sudo -u postgres pgbackrest info
stanza: prod
status: ok
cipher: none
db (current)
wal archive min/max (16): 000000010000004A00000090/000000010000004A000000A1
full backup: 2025-12-31 03:00:02+00
size: 612.3GB, repo size: 201.7GB
backup reference list:
Significado: Existe un full backup reciente y el rango de WAL archive está presente. Si el status no es ok o WAL min/max está desactualizado, tu PITR podría ser imposible.
Decisión: Si el WAL archive no está sano, deja de prometer PITR. Promueve una réplica o restaura hasta el último punto válido.
Tarea 6: Identificar presión de checkpoint en PostgreSQL (cliff de rendimiento post-restore)
cr0x@server:~$ sudo -u postgres psql -c "select checkpoints_timed, checkpoints_req, buffers_checkpoint, buffers_backend, stats_reset from pg_stat_bgwriter;"
checkpoints_timed | checkpoints_req | buffers_checkpoint | buffers_backend | stats_reset
------------------+-----------------+--------------------+-----------------+-------------------------------
112 | 87 | 98122310 | 442190 | 2025-12-31 09:40:00+00
(1 row)
Significado: Un alto checkpoints_req sugiere checkpoints forzados (a menudo debido a max_wal_size demasiado pequeño o ráfagas de escritura). Eso puede ralentizar la recuperación y el tráfico inicial.
Decisión: Incrementa max_wal_size y ajusta checkpoint_timeout/checkpoint_completion_target para un I/O más suave—especialmente en nodos de recuperación.
Tarea 7: Comprobar comportamiento de recuperación de InnoDB en MariaDB y pistas de tiempo de crash recovery
cr0x@server:~$ sudo tail -n 40 /var/log/mysql/error.log
2025-12-31 10:11:22 0 [Note] InnoDB: Starting crash recovery.
2025-12-31 10:11:22 0 [Note] InnoDB: Reading tablespace information from the .ibd files...
2025-12-31 10:12:10 0 [Note] InnoDB: 5.6.0 started; log sequence number 987654321
2025-12-31 10:12:10 0 [Note] InnoDB: Completed initialization of buffer pool
2025-12-31 10:12:54 0 [Note] InnoDB: Crash recovery finished.
Significado: Si la recuperación por crash toma minutos, eso forma parte de tu RTO. Tiempos más largos a menudo se correlacionan con redo logs grandes, volumen de páginas sucias o fsync lento.
Decisión: Si la recuperación por crash es consistentemente larga, ajusta checkpointing/flush y asegura que redo logs y datos vivan en almacenamiento de baja latencia.
Tarea 8: Validar preparación del backup físico de MariaDB (prepared vs not)
cr0x@server:~$ sudo mariabackup --prepare --target-dir=/backups/mariadb/full-2025-12-31
[00] 2025-12-31 10:14:03 completed OK!
Significado: “completed OK” significa que el backup ahora es consistente y está listo para un copy-back rápido. Si retrasas el prepare hasta el tiempo de incidente, te acabas de gastar tu RTO en trámites.
Decisión: Mantén siempre el último backup ya preparado (o prepáralo inmediatamente después de crearlo) si buscas restauraciones por debajo de 15 minutos.
Tarea 9: Restaurar MariaDB desde backup preparado (copy-back) y verificar propiedad
cr0x@server:~$ sudo systemctl stop mariadb
cr0x@server:~$ sudo rm -rf /var/lib/mysql/*
cr0x@server:~$ sudo mariabackup --copy-back --target-dir=/backups/mariadb/full-2025-12-31
[00] 2025-12-31 10:15:44 completed OK!
cr0x@server:~$ sudo chown -R mysql:mysql /var/lib/mysql
Significado: El éxito del copy-back es necesario pero no suficiente. La propiedad incorrecta impedirá el arranque o causará fallos de permisos extraños.
Decisión: Si la propiedad/SELinux/AppArmor es incorrecta, arréglala ahora. No “intentes ver si arranca”. No lo hará y perderás tiempo.
Tarea 10: Confirmar que MariaDB acepta conexiones y no está atascado en recovery
cr0x@server:~$ sudo systemctl start mariadb
cr0x@server:~$ mysql -uroot -e "select @@version, @@innodb_flush_log_at_trx_commit, @@sync_binlog\G"
@@version: 10.11.6-MariaDB
@@innodb_flush_log_at_trx_commit: 1
@@sync_binlog: 1
Significado: El servidor está arriba y las configuraciones son visibles. Si la conexión cuelga, revisa el error log por recuperación por crash o stalls de fsync.
Decisión: Para nodos de restauración de emergencia, puedes relajar temporalmente la durabilidad (ver más adelante) si tu organización lo acepta—luego revierte.
Tarea 11: Estimar tiempo de restauración de PostgreSQL midiendo descompresión y copia
cr0x@server:~$ time sudo -u postgres pgbackrest --stanza=prod restore --type=immediate --target-action=promote
real 6m42.118s
user 2m10.044s
sys 1m02.991s
Significado: “real” es el reloj de pared. Si el tiempo user es enorme, la descompresión/encriptación está limitada por CPU. Si sys es grande, el kernel y el I/O son la historia.
Decisión: CPU-bound: añade cores, cambia la compresión, paraleliza. I/O-bound: discos más rápidos, repo local, menos saltos de red.
Tarea 12: Comprobar si PostgreSQL está esperando la recuperación del WAL archive
cr0x@server:~$ sudo -u postgres psql -c "select now(), wait_event_type, wait_event, state, query from pg_stat_activity where pid = pg_backend_pid();"
now | wait_event_type | wait_event | state | query
------------------------------+-----------------+------------+--------+-------------------------------------
2025-12-31 10:17:12.118+00 | Activity | WALRead | active | select now(), wait_event_type, ...
(1 row)
Significado: Espera WALRead durante la recuperación a menudo indica I/O o lentitud en el fetch del archive.
Decisión: Si el WAL está remoto, acerca el archive o cambia a streaming desde una fuente viva; si es local, investiga la latencia del disco.
Tarea 13: Detectar un replication slot olvidado que está inflando WAL (higiene previa al incidente)
cr0x@server:~$ sudo -u postgres psql -c "select slot_name, active, restart_lsn from pg_replication_slots;"
slot_name | active | restart_lsn
---------------+--------+-------------
analytics_etl | f | 4A/01000000
(1 row)
Significado: Un slot inactivo retiene WAL. Con el tiempo, eso infla el volumen de WAL, que infla el tiempo de PITR y puede llenar discos en el peor momento.
Decisión: Si el consumidor está muerto, elimina el slot tras confirmar que es seguro. Luego arregla la gestión de consumidores.
Tarea 14: Comprobar disponibilidad de binlog de MariaDB para PITR y el reloj contra el que compites
cr0x@server:~$ mysql -uroot -e "show binary logs;"
Log_name File_size
binlog.000221 104857600
binlog.000222 104857600
binlog.000223 51239871
Significado: Existen binlogs y los tamaños sugieren rotación activa. Si faltan logs porque la retención es demasiado corta, PITR es una fantasía.
Decisión: Configura la retención de binlog basada en la ventana máxima de PITR que prometes. Luego vigílala como si fuera producción (porque lo es).
Tarea 15: Validar el éxito de la restauración comprobando invariantes clave (PostgreSQL)
cr0x@server:~$ sudo -u postgres psql -c "select count(*) from pg_class; select now();"
count
-------
4182
(1 row)
now
-------------------------------
2025-12-31 10:18:55.11002+00
(1 row)
Significado: No estás probando la corrección, pero sí que el catálogo es legible y el servidor responde. Añade chequeos a nivel de aplicación después.
Decisión: Si alguna consulta da errores por corrupción, para. Cambia a promoción de réplica o a otro backup inmediatamente.
Tarea 16: Validar el éxito de la restauración comprobando invariantes clave (MariaDB)
cr0x@server:~$ mysql -uroot -e "show engine innodb status\G" | head -n 25
*************************** 1. row ***************************
Type: InnoDB
Name:
Status:
=====================================
2025-12-31 10:19:21 0x7f2c4c1fe700 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 4 seconds
-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 12 srv_active, 0 srv_shutdown, 245 srv_idle
Significado: InnoDB está arriba. También puedes ver si aún realiza mucho trabajo en background. Si está thrashing, espera un comportamiento lento de la app aunque la “restauración esté hecha”.
Decisión: Considera reducir temporalmente el tráfico de la app o habilitar modo solo lectura hasta que el sistema se estabilice, dependiendo de tu modelo de servicio.
Tres mini-historias de la vida corporativa
Mini-historia 1: El outage provocado por una suposición equivocada
La empresa estaba en medio de una migración: un monolito en MariaDB y un nuevo servicio en PostgreSQL. El equipo SRE tenía un objetivo de RTO claro y una realidad desordenada. Todos coincidieron en “tenemos backups”, que es el equivalente corporativo a decir “tenemos paraguas” mientras están en medio de un huracán.
La suposición era simple: los dumps lógicos son “suficientes” porque el dataset “no es tan grande”. Nadie había cronometrado realmente una restauración de extremo a extremo. El runbook de on-call decía: sacar el último dump del objeto storage, restaurar, aplicar migraciones, apuntar la app.
Entonces un incidente de almacenamiento destruyó un volumen primario. El equipo inició la restauración desde el dump. Avanzó lentamente, la CPU se saturó, el disco se encendió y el reloj siguió corriendo. La creación de índices dominó. Luego las migraciones de la app se ejecutaron y añadieron más locks y más tiempo. Después de una hora, tenían una base de datos. Tras más tiempo, tenían algo que la app podía usar. El RTO no se perdió por minutos; se perdió por toda una reunión.
El postmortem no trató de un ajuste heroico. Se trató de admitir que los dumps no son una estrategia de restauración a escala. Implementaron backups físicos, construyeron un standby caliente y empezaron a cronometrar restauraciones mensuales. La solución fue mayormente poco glamorosa. Por eso funcionó.
Mini-historia 2: La optimización que salió mal
Otra organización se enorgullecía de su eficiencia de almacenamiento. Comprimían todo agresivamente: backups base, WAL archives, todo. Los costes bajaron. Los dashboards se veían limpios. Finanzas estuvo brevemente encantado.
Durante un incidente real, restauraron PostgreSQL desde un backup comprimido a un nodo con menos cores que producción. En papel “estaba bien”, porque ese nodo existía sólo para emergencias. En realidad, la descompresión se convirtió en el cuello de botella. La restauración tardó tanto que el equipo empezó a “optimizar” en vivo: cambiar ajustes de compresión a mitad de la operación, reiniciar procesos y, en general, convertir un procedimiento predecible en danza interpretativa.
Recuperaron la base de datos, pero su objetivo de RTO se perdió. Lo más doloroso: los ahorros en almacenamiento eran reales, pero minúsculos comparados con el coste del outage y el daño a la reputación. Reajustaron: compresión moderada, más paralelismo y nodos de restauración de emergencia dimensionados para cargas de restauración, no para cargas steady-state.
Broma #2: Nada dice “estamos preparados” como descubrir que tu caja de disaster-recovery es básicamente una patata con un cable de red.
Mini-historia 3: La práctica aburrida pero correcta que salvó el día
Una compañía vinculada a pagos operaba MariaDB y PostgreSQL para distintos servicios. Su hábito más valioso no era una herramienta. Era un ritual: cada semana, un ingeniero realizaba un ensayo de restauración en un entorno aislado, usando los mismos comandos que requería el runbook de incidentes.
Llevaban tres tiempos: tiempo para provisionar compute y almacenamiento, tiempo para restaurar el backup base y tiempo para alcanzar “app saludable”. También registraban las razones de fallo—permisos, segmentos WAL faltantes, drift de esquema, secretos rotos—y las arreglaban con la clase de crueldad calmada que solo un drill recurrente puede inspirar.
Cuando llegó un incidente (un volumen corrupto más una actualización de kernel mala, porque la realidad disfruta de combo), la restauración no fue perfecta. Pero estaba practicada. Ejecutaron el playbook, vieron el lag de WAL inmediatamente, cambiaron a promoción de réplica y volvieron dentro de la ventana.
Nadie escribió un mensaje heroico en Slack después. Así sabes que funcionó.
Errores comunes: síntomas → causa raíz → solución
Esta es la sección que lees cuando la restauración está “casi lista” por quinta vez.
1) Síntoma: la restauración empieza rápido y luego se arrastra al 5–10% de CPU
- Causa raíz: latencia de I/O y stalls de fsync, a menudo debido a almacenamiento compartido o créditos de ráfaga agotados.
- Solución: Mueve datos y WAL/redo a SSD/NVMe de baja latencia; reduce vecinos ruidosos; verifica el presupuesto de IOPS; considera rollback por snapshot o promoción de réplica.
2) Síntoma: PostgreSQL atascado en “restoring log file … from archive” lentamente
- Causa raíz: cuello de botella en la recuperación del WAL archive (latencia del object store remoto, fetch serial o red limitada).
- Solución: Usa un repo/caché local para WAL, habilita recuperación WAL paralela en tu herramienta de backup o haz streaming desde un upstream en vivo si está disponible.
3) Síntoma: arranque de MariaDB tarda una eternidad después del copy-back
- Causa raíz: la recuperación por crash de InnoDB aplica redo lentamente; con frecuencia ajustes de log y latencia del almacenamiento se combinan para castigarte.
- Solución: Mantén backups preparados; asegura que redo log y datos estén en almacenamiento rápido; revisa innodb_flush_log_at_trx_commit y sync_binlog para el nodo de recuperación si es aceptable.
4) Síntoma: “backup restaurado” pero explotan errores de la aplicación
- Causa raíz: la restauración levantó la BD, pero no el entorno: usuarios erróneos, extensiones faltantes, drift de configuración o DNS/connection strings obsoletos.
- Solución: Automatiza smoke tests post-restore; gestiona roles/extensiones vía gestión de configuración; aplica configs inmutables para targets de restauración.
5) Síntoma: PITR falla a mitad de camino por falta de WAL/binlog
- Causa raíz: retención demasiado corta, archivado no monitorizado o un gap creado durante un incidente anterior.
- Solución: Monitorea la continuidad del archive; alerta por segmentos faltantes; ajusta retención para coincidir con la ventana prometida; practica restauraciones para demostrarlo.
6) Síntoma: las restauraciones son rápidas en pruebas, lentas en incidentes reales
- Causa raíz: las pruebas se ejecutan en hosts vacíos y con almacenamiento tranquilo; los incidentes ocurren durante la contención y modos degradados.
- Solución: Prueba restauraciones bajo carga y con contención de I/O realista; reserva capacidad de restauración; mantiene nodos de recuperación dimensionados y calientes.
Listas de verificación / plan paso a paso
Paso a paso: llegar a RTO sub-15 minutos (el camino práctico)
- Elige tu estrategia de recuperación según el tamaño del dataset. Si tu directorio de datos es lo bastante grande como para que copiarlo lleve más de 10 minutos, deja de fingir. Usa promoción de réplica o snapshots.
- Estandariza en backups físicos para ambos motores. MariaDB: Mariabackup. PostgreSQL: pgBackRest (o herramienta física equivalente). Los dumps pasan a secundarios.
- Prepara localmente el backup base más reciente. Tu nodo de restauración no debería estar descargando cientos de gigabytes por una red best-effort durante un incidente.
- Mantén los backups “listos para restaurar”. Para MariaDB, eso significa backups preparados. Para PostgreSQL, eso significa manifiestos/checksums verificados y un archive que realmente contenga lo que necesitas.
- Diseña PITR como un sistema de primera clase. El archivado WAL/binlog debe ser monitorizado, retenido y probado. Trata las brechas como Sev-2, no como “lo arreglaremos después”.
- Provisiona nodos de recuperación para la carga de restauración. La restauración es bursty: I/O alto, CPU alto (descompresión), muchas operaciones de metadata. Dimensiona para eso, no para el QPS promedio.
- Separa volúmenes de datos y logs cuando ayude. PostgreSQL: mantén WAL en almacenamiento rápido. MariaDB: los archivos de log y datos se benefician de baja latencia; la separación puede reducir la contención.
- Escribe un runbook de una página con árbol de decisiones. “Si el archive WAL es lento, promueve réplica.” Hazlo ejecutable a las 3 a.m.
- Automatiza el corte de servicio. Actualizaciones DNS/VIP, strings de conexión, reload de poolers. Tu RTO muere en los pasos pegajosos.
- Ensaya mensualmente con cronómetro. Registra tres tiempos: restore base, recovery a consistencia, app saludable. Arregla el mayor sumidero de tiempo primero.
Tácticas de configuración que suelen ayudar (y cuándo tener cuidado)
No son perillas universales de “hazlo rápido”. Son palancas. Tíralas con intención, y preferiblemente sólo en nodos de recuperación o durante ventanas de recuperación.
- PostgreSQL: Asegura que la recuperación del WAL archive sea rápida (cache local); afina ajustes de checkpoint para tu carga; evita max_wal_size pequeño en sistemas con mucha escritura; dimensiona shared_buffers sensiblemente (demasiado grande puede ralentizar el restart por más buffers sucios).
- MariaDB: Mantén backups preparados; evita settings de flush patológicos que creen recovery por crash masivo; asegura estrategia de warm-up del buffer pool si dependes de ella; considera retrasar algo de durabilidad sólo si tu postura de riesgo lo permite.
FAQ
1) ¿Cuál restaura más rápido: MariaDB o PostgreSQL?
Ninguno “gana” universalmente. La restauración física de PostgreSQL más el replay de WAL es extremadamente predecible cuando el archive WAL está sano y local. MariaDB puede restaurar físicamente muy rápido, pero el comportamiento de recuperación de InnoDB y la aplicación de binlog pueden sorprenderte. Tu almacenamiento y tu estrategia PITR deciden el ganador más que la marca del motor.
2) ¿Puedo alcanzar RTO de 15 minutos con mysqldump o pg_dump?
Sólo para datasets pequeños y esquemas simples. Una vez que los índices y constraints son significativos, el tiempo de restauración lógica se dispara. Para RTO estrictos, usa backups físicos, snapshots o promoción de réplica.
3) ¿Cuál es el factor único más grande en el tiempo de restauración?
Para restauraciones físicas: latencia del almacenamiento (I/O fsync-heavy) y throughput de replay de logs (WAL/redo). Para PITR: velocidad de recuperación del archive y continuidad.
4) ¿Cómo se comparan los snapshots con los backups físicos?
Los snapshots (EBS/ZFS/LVM) pueden ser la “restauración” más rápida si son crash-consistent y la base de datos lo tolera (usualmente con recovery). También son fáciles de usar mal: snapshotear el conjunto de volúmenes equivocado o olvidar que necesitas snapshots consistentes entre datos y volúmenes WAL.
5) ¿Deberían WAL/binlog ir en discos separados?
A menudo sí, cuando reduce contención y da a los logs menor latencia. Pero discos separados no arreglan discos lentos. Un NVMe rápido puede vencer a dos volúmenes de red mediocres cualquier día de la semana.
6) ¿La compresión ayuda la velocidad de restauración?
Ayuda el tiempo de transferencia y la huella de almacenamiento, pero puede perjudicar el tiempo de restauración si la operación está limitada por CPU o es single-thread. La compresión moderada con paralelismo suele ser el punto óptimo para sistemas enfocados en RTO.
7) ¿Cómo demuestro que mi RTO es real?
Cronometra un ensayo completo: provisionar → restaurar → recovery/PITR → chequeos de salud de la app → corte. Hazlo bajo carga realista y con las mismas personas que estarán en on-call.
8) ¿Qué debo monitorizar para proteger la velocidad de restauración?
Continuidad de WAL/binlog archive, éxito y validación de backups, lag de replicación, latencia de almacenamiento, espacio libre en disco (incluyendo crecimiento de WAL) y “tiempo de ensayo de restauración” como SLO de primera clase.
9) Si puedo promover una réplica, ¿sigo necesitando backups?
Sí. Las réplicas protegen contra algunas fallas (muerte de nodo). Los backups protegen contra otras fallas (error humano, corrupción de datos, despliegues malos, ransomware). El RTO viene de las réplicas; la recuperación de datos malos viene de los backups.
Próximos pasos que puedes hacer esta semana
- Cronometra una restauración para MariaDB y PostgreSQL en un entorno staging, de extremo a extremo, con cronómetro. Registra dónde se va el tiempo: copia, prepare, replay WAL/binlog, disponibilidad de la app.
- Ejecuta las pruebas de latencia de almacenamiento (fio random write) en tus nodos de recuperación reales. Si la latencia es mala, tu objetivo de RTO es ficción hasta que cambies almacenamiento.
- Valida los inputs de PITR: comprueba el rango del WAL archive (PostgreSQL) o la retención de binlog (MariaDB). Configura alertas por brechas.
- Cambia tu runbook a un árbol de decisiones: “restaurar desde backup” vs “promover réplica” vs “rollback por snapshot”. Haz explícitos los trade-offs.
- Programa un ensayo de restauración mensual y trata los fallos como incidentes de producción. Si no puedes restaurar un martes, no restaurarás un domingo.
RTO inferior a 15 minutos no es un ejercicio de tuning. Es una elección de cultura operativa: backups físicos, artefactos staged, almacenamiento rápido y ensayos que hacen del camino aburrido la opción por defecto. Haz eso y las restauraciones serán un procedimiento. Sáltatelo y las restauraciones serán una historia.