DEV Community

Cover image for pgbackrest dejó de mantenerse: qué hago ahora con mis backups de Postgres en producción
Juan Torchia
Juan Torchia

Posted on • Originally published at juanchi.dev

pgbackrest dejó de mantenerse: qué hago ahora con mis backups de Postgres en producción

pgbackrest dejó de mantenerse: qué hago ahora con mis backups de Postgres en producción

Hacer un backup es básicamente como anotarte un número de teléfono en una servilleta. La servilleta existe, el número está ahí, sentís que estás cubierto. Pero el día que necesitás llamar y la servilleta desapareció en el fondo de un bolsillo de jean que pasó por el lavarropas — ese día entendés que nunca tuviste un plan de recuperación. Tenías una ilusión de plan.

Eso es lo que el thread de HN sobre pgbackrest me hizo caer: yo tenía una servilleta mojada.


pgbackrest alternativa postgres backup producción: el contexto que importa

El thread llegó a 425 puntos en Hacker News con un comentario que no dejaba mucho lugar a la duda: el mantenedor principal ya no tiene tiempo, los PRs se acumulan sin revisión y la dirección del proyecto está en pausa indefinida. No es un repo abandonado todavía, pero tampoco es algo en lo que querrías apoyar una base de datos que aloja datos de usuarios reales.

Yo lo usaba. No como primera línea, pero sí como parte del flujo de backup incremental que armé hace dos años cuando el agente me borró la base de datos en producción. Después de ese episodio prometí que nunca más iba a depender de un solo mecanismo de recovery. pgbackrest era la capa que manejaba los backups incrementales con compresión y retención por tiempo. Funcionaba. Hasta que dejó de tener sentido seguir dependiendo de algo sin maintainer activo.

Mi tesis: la muerte de un proyecto de infra no es el problema en sí — es el detector de humo que te avisa que nunca probaste realmente recuperar nada. El problema estaba antes. El thread de HN solo lo hizo visible.


Qué opciones evalué y con qué criterio

Antes de saltar a la alternativa de moda, me obligué a definir qué necesitaba realmente. Mi stack: PostgreSQL 16 corriendo en Railway, base de datos de ~4.2 GB, WAL archiving habilitado, retention de 30 días, RTO informal de "menos de 2 horas" que nunca había medido concretamente.

Las tres opciones que evalué en serio:

1. WAL-G

Open source, mantenido activamente por Wal-G Inc. (antes parte del stack de Citus/Microsoft), soporte nativo para S3, GCS, Azure y filesystem local. La ventaja más concreta es que el binario es autocontenido — no hay dependencias raras que gestionar.

# Instalación básica en Debian/Ubuntu
curl -L https://github.com/wal-g/wal-g/releases/latest/download/wal-g-pg-ubuntu-20.04-amd64.tar.gz \
  | tar -xz -C /usr/local/bin/

# Variables de entorno mínimas para S3
export WALG_S3_PREFIX="s3://mi-bucket-backups/postgres"
export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."
export PGDATA="/var/lib/postgresql/16/main"

# Backup base completo
wal-g backup-push $PGDATA

# Listar backups disponibles
wal-g backup-list DETAIL

# Restore a punto específico en el tiempo
wal-g backup-fetch $PGDATA LATEST
Enter fullscreen mode Exit fullscreen mode

Lo que me sorprendió: en mis pruebas de restore, WAL-G tardó 18 minutos en recuperar los 4.2 GB desde S3 incluyendo aplicación de WAL hasta el punto en el tiempo que elegí. Ese número lo medí tres veces con un script simple.

2. Barman (Backup and Recovery Manager)

Mantenido por EnterpriseDB, mucho más maduro en términos de interfaz operacional. La curva de configuración es empinada — hay un servidor Barman separado que actúa como receptor de backups, lo que implica infraestructura adicional.

# barman.conf básico (en el servidor Barman dedicado)
[barman]
barman_home = /var/lib/barman
barman_user = barman
log_file = /var/log/barman/barman.log
compression = gzip
reuse_backup = link  # hardlinks para backups incrementales eficientes

[mi-postgres-server]
description = "Producción principal"
conninfo = host=postgres-host user=barman dbname=postgres
backup_method = rsync
archiver = on
retention_policy = RECOVERY WINDOW OF 30 DAYS

# Verificar configuración
barman check mi-postgres-server

# Backup
barman backup mi-postgres-server

# Listar
barman list-backup mi-postgres-server

# Restore
barman recover mi-postgres-server latest /var/lib/postgresql/16/main \
  --target-time "2025-07-10 14:30:00"
Enter fullscreen mode Exit fullscreen mode

El tiempo de restore de Barman en el mismo escenario: 31 minutos. Casi el doble. La razón principal es que Barman usa rsync por defecto y tiene overhead de coordinación entre servidores. Con backup_method = postgres (streaming) baja, pero igual no gana.

3. pg_dump puro con rotación manual

La opción más honesta. La que todo el mundo conoce, nadie quiere usar para producción seria, y que muchas veces es la única que sobrevive cuando todo lo demás falla.

#!/bin/bash
# Script de backup con pg_dump — sin magia, sin dependencias externas
# Guardado en /usr/local/bin/pg_backup_diario.sh

set -euo pipefail

TIMESTAMP=$(date +%Y%m%d_%H%M%S)
DB_NAME="mi_base"
BACKUP_DIR="/mnt/backups/postgres"
RETENTION_DAYS=14

# Backup comprimido
pg_dump -Fc \
  --no-password \
  -h $PGHOST \
  -U $PGUSER \
  -d $DB_NAME \
  > "$BACKUP_DIR/${DB_NAME}_${TIMESTAMP}.dump"

# Rotación automática
find "$BACKUP_DIR" -name "*.dump" -mtime +$RETENTION_DAYS -delete

# Log del tamaño real del dump
du -sh "$BACKUP_DIR/${DB_NAME}_${TIMESTAMP}.dump" >> /var/log/pg_backup.log

echo "Backup completado: ${TIMESTAMP}" >> /var/log/pg_backup.log
Enter fullscreen mode Exit fullscreen mode

Restore con pg_dump es 23 minutos para los 4.2 GB. Más rápido que Barman, más lento que WAL-G, pero sin PITR (Point in Time Recovery). Si necesitás recuperar a las 14:37 y el backup más cercano es de las 14:00, perdiste 37 minutos de datos. Ese trade-off es el que más duele en producción real.


Lo que los benchmarks de popularidad no te dicen

El problema con elegir herramientas de infra por GitHub stars o por cuánta gente las menciona en Reddit es que la popularidad mide adopción, no idoneidad para el caso específico. pgbackrest tiene más de 3.000 estrellas. Eso no me ayudó cuando necesité entender cuánto tarda mi base puntual en recuperarse.

Lo que sí me ayudó: medir. Tres scenarios distintos:

Herramienta Restore completo (4.2 GB) PITR disponible Overhead infra Costo storage (30 días)
WAL-G 18 min Mínimo ~$0.92/mes en S3
Barman 31 min Servidor dedicado ~$0.92/mes + EC2
pg_dump 23 min No Ninguno ~$0.85/mes en S3

El costo de storage en S3 es casi el mismo porque WAL-G comprime agresivamente y los WAL archivados son razonablemente chicos para una base que no tiene escrituras masivas. Pero si Railway o Supabase fueran mi opción de managed Postgres, el WAL archiving externo ya viene resuelto o directamente no está disponible para configurar manualmente.

Ese detalle me hizo revisar por qué migré ciertas cosas a infra propia — el control sobre cómo y dónde guardás los datos de recovery no es un tema menor cuando el proveedor decide qué features exponés.


Los errores que cometí (y que vas a cometer si no los revisás ahora)

Error 1: nunca restauré de verdad

Tenía backups funcionando desde hacía dos años. Nunca hice un restore completo a un ambiente de staging para medir el tiempo real. El número que tenía en la cabeza ("backup de Postgres, menos de una hora") era completamente inventado. Mi primer restore real en un ambiente limpio tardó 47 minutos con pgbackrest — casi el doble de lo que asumía.

Si no corriste un restore completo en el último mes, no tenés un plan de recovery. Tenés una servilleta mojada.

Error 2: confundir backup con archive

WAL archiving y backups base son dos cosas distintas que trabajan juntas. Si solo tenés WAL archiving sin un backup base reciente, el tiempo de restore va a ser proporcional a cuántos WAL files necesitás aplicar desde el último base backup. En mi caso, con un base backup semanal y WAL continuo, el peor escenario eran 7 días de WAL — varios minutos adicionales de replay.

# Ver cuántos WAL segments hay desde el último backup
# En WAL-G:
wal-g wal-show

# Salida esperada — prestá atención al "segments" count
# +---------------------------+----------+---------+
# | Start                     | End      |Segments |
# +---------------------------+----------+---------+
# | 2025-07-04T03:00:00+00:00 | current  |    1842 |
# +---------------------------+----------+---------+
# 1842 segments = tiempo de replay no trivial
Enter fullscreen mode Exit fullscreen mode

Error 3: ignorar el WAL size en producción

Mi base tiene 4.2 GB de datos, pero genera aproximadamente 180 MB de WAL por día. En 30 días: ~5.4 GB de WAL adicional archivado. Si no lo medís, el costo de storage se va silenciosamente. En S3 es barato, pero en otros providers puede sorprender.

# Medir generación de WAL en las últimas 24hs
SELECT
  count(*) as wal_files_generados,
  pg_size_pretty(sum(size)) as tamanio_total
FROM pg_ls_waldir()
WHERE modification > now() - interval '24 hours';
Enter fullscreen mode Exit fullscreen mode

Este tipo de medición es exactamente lo que los logs de producción revelan cuando te forzás a mirarlos en frío, sin la adrenalina de un incidente.


FAQ: pgbackrest alternativa postgres backup producción

¿WAL-G es un reemplazo directo de pgbackrest?

Funcionalmente sí, en la mayoría de los casos. Ambos manejan backups base + WAL archiving con PITR. La diferencia principal está en la configuración: WAL-G es más simple de arrancar (un binario, variables de entorno) mientras que pgbackrest tiene un archivo de configuración más expresivo. Si ya tenés pgbackrest configurado, la migración a WAL-G implica reescribir la config y hacer un primer backup base completo desde cero — no podés reutilizar los backups existentes de formato distinto.

¿Barman sigue valiendo la pena si ya tenés infra dedicada?

Sí, especialmente si manejás múltiples instancias de Postgres y necesitás una interfaz operacional centralizada con auditoría. El overhead de tener un servidor Barman separado se amortiza cuando gestionás 5+ instancias desde un solo lugar. Para una sola instancia como la mía, es overkill con costo real.

¿pg_dump alcanza para producción o es solo para desarrollo?

Depende de tu RTO y RPO. Si podés tolerar pérdida de hasta N horas de datos (donde N es la frecuencia de dumps) y un restore de 20-40 minutos no te rompe ningún SLA, pg_dump con rotación automatizada es completamente válido. La limitación real es la ausencia de PITR: no podés recuperar a un punto exacto entre dos dumps. Para bases transaccionales críticas, eso suele ser inaceptable.

¿Cómo configuro WAL archiving en Railway o Supabase?

En Railway con Postgres custom podés configurar archive_mode = on y archive_command si tenés acceso al postgresql.conf. En Supabase el WAL archiving es interno al servicio — podés usar Point in Time Recovery dentro de la plataforma pero no exportar WAL a storage externo directamente. Eso es un vendor lock-in de recovery que vale la pena evaluar según la criticidad del dato.

¿Qué frecuencia de backup base tiene sentido?

Para la mayoría de los casos: backup base diario + WAL continuo. Un backup base semanal con WAL continuo es aceptable si la base crece lento (bajo 500 MB/día de WAL). Con backup base diario, el replay de WAL en restore es mínimo. Con backup semanal, en el peor caso necesitás aplicar 7 días de WAL — eso puede sumar decenas de minutos dependiendo del volumen de escritura.

¿Vale la pena esperar a ver si pgbackrest retoma el mantenimiento?

No. En sistemas de infra, un maintainer que anuncia falta de tiempo disponible raramente vuelve con más energía. La ventana de riesgo entre "proyecto sin mantenimiento activo" y "vulnerabilidad crítica sin parchear" puede ser corta. Migrá ahora con tiempo, no durante un incidente. El costo de migrar en calma es infinitamente menor que el costo de migrar bajo presión — algo que aprendí la noche que tiré un servidor de producción con rm -rf en mi primera semana de laburo.


Qué elegí y por qué no es la respuesta para todos

Me quedé con WAL-G + pg_dump como segunda línea.

WAL-G maneja los backups incrementales con PITR. pg_dump corre cada 24 horas y va a un bucket S3 separado como fallback independiente — sin dependencias de herramientas de terceros, sin binarios especiales, solo pg_dump y aws s3 cp. Si WAL-G desapareciera mañana, tengo un dump de ayer.

El criterio que usé no fue "qué tool tiene más stars" sino "qué tan rápido puedo recuperar y con cuántas dependencias en la cadena de recovery". Menos dependencias en el path crítico es mejor. Cuando tenés que restaurar una base de datos, cada pieza adicional que puede fallar es un problema que no necesitás.

Lo que no elegiría para mi caso: Barman en una sola instancia. El overhead operacional no cierra. Puede tener sentido para equipos con múltiples bases y un DBA dedicado — pero eso no es mi realidad.

Lo incómodo de todo esto: pasé dos años con pgbackrest sin haber medido un restore real. El thread de HN no me rompió la infra — me rompió la tranquilidad falsa. Y eso, a la larga, fue mejor que seguir con una servilleta mojada en el bolsillo.

Si querés revisar qué más puede estar en estado de "funciona hasta que no funciona" en la capa de datos, el post sobre migrar de Notion a Markdown tiene algo de ese mismo sabor: la dependencia silenciosa que solo duele cuando intentás salir.

Y si hacés el switch a WAL-G, medí el restore. No lo asumas. El número real siempre es distinto del número imaginado.


¿Estás migrando de pgbackrest o evaluando opciones? Escribime — estoy armando un repositorio de configuraciones reales de WAL-G para Railway específicamente.


Este artículo fue publicado originalmente en juanchi.dev

Top comments (0)