Desde hace tiempo se sabe que hacer copias de seguridad en volcado SQL (usando pg_dump o pg_dumpall) no es la mejor idea. Para respaldar bases de datos PostgreSQL, es mejor usar el comando pg_basebackup, que crea una copia binaria de los registros WAL. Pero cuando comiences a estudiar todo el proceso de creación de copias y restauración, entenderás que necesitas escribir al menos un par de bicicletas de tres ruedas para que todo funcione y no te cause dolor ni arriba ni abajo. Para aliviar las penurias, se desarrolló WAL-G.
– es una herramienta escrita en Go para la copia de seguridad y restauración de bases de datos PostgreSQL (y desde hace poco también de MySQL/MariaDB, MongoDB y FoundationDB). Soporta el trabajo con almacenes Amazon S3 (y análogos, como Yandex Object Storage), así como Google Cloud Storage, Azure Storage, Swift Object Storage y simplemente con el sistema de archivos. Toda la configuración se reduce a pasos simples, pero debido a que los artículos sobre él son dispersos en Internet, no hay un manual completo que incluya todos los pasos de principio a fin (en Habr hay algunas publicaciones, pero se omiten muchos puntos).

Este artículo está escrito principalmente para sistematizar mis conocimientos. No soy DBA y en algunos casos puedo expresarme con un lenguaje más técnico, ¡así que agradezco cualquier corrección!
Cabe señalar que todo lo que se incluye a continuación es relevante y verificado para PostgreSQL 12.3 en Ubuntu 18.04; todos los comandos deben ejecutarse como usuario privilegiado.
Instalación
En el momento de escribir este artículo, la versión estable de WAL-G es . Esta es la que usaremos (pero si deseas compilarlo tú mismo desde la rama master, en el repositorio de GitHub hay todas las instrucciones para hacerlo). Para descargar e instalar, debes ejecutar:
#!/bin/bash
curl -L "https://github.com/wal-g/wal-g/releases/download/v0.2.15/wal-g.linux-amd64.tar.gz" -o "wal-g.linux-amd64.tar.gz"
tar -xzf wal-g.linux-amd64.tar.gz
mv wal-g /usr/local/bin/
Después de esto, primero debes configurar WAL-G y luego PostgreSQL.
Configuración de WAL-G
Para el ejemplo de almacenamiento de copias de seguridad, se usará Amazon S3 (porque está más cerca de mis servidores y su uso resulta muy barato). Para trabajar con él, se necesita un 'bucket' S3 y claves de acceso.
En todos los artículos anteriores sobre WAL-G se utilizaba la configuración mediante variables de entorno, pero a partir de esta versión se pueden colocar configuraciones en en el directorio home del usuario postgres. Para crearlo, ejecutaremos el siguiente script bash:
#!/bin/bash
cat > /var/lib/postgresql/.walg.json << EOF
{
"WALG_S3_PREFIX": "s3://your_bucket/path",
"AWS_ACCESS_KEY_ID": "key_id",
"AWS_SECRET_ACCESS_KEY": "secret_key",
"WALG_COMPRESSION_METHOD": "brotli",
"WALG_DELTA_MAX_STEPS": "5",
"PGDATA": "/var/lib/postgresql/12/main",
"PGHOST": "/var/run/postgresql/.s.PGSQL.5432"
}
EOF
# обязательно меняем владельца файла:
chown postgres: /var/lib/postgresql/.walg.json
Voy a explicar un poco sobre todos los parámetros:
- WALG_S3_PREFIX – ruta a su bucket S3 donde se cargarán las copias de seguridad (puede ser en la raíz o en una carpeta);
- AWS_ACCESS_KEY_ID – clave de acceso en S3 (en caso de restauración en un servidor de prueba, estas claves deben tener una política de solo lectura. Más detalles sobre esto se encuentran en la sección sobre restauración.);
- AWS_SECRET_ACCESS_KEY – clave secreta en el almacenamiento S3;
- WALG_COMPRESSION_METHOD – método de compresión, es mejor usar Brotli (ya que es el término medio entre el tamaño final y la velocidad de compresión/descompresión);
- WALG_DELTA_MAX_STEPS – número de "deltas" antes de crear una copia de seguridad completa (ahorran tiempo y espacio en los datos cargados, pero pueden retrasar un poco el proceso de restauración, por lo que no se recomienda usar valores grandes);
- PGDATA – ruta al directorio con los datos de su base de datos (se puede averiguar ejecutando el comando pg_lsclusters);
- PGHOST – conexión a la base de datos, en la copia de seguridad local es mejor hacerlo a través de unix-socket como en este ejemplo.
Los demás parámetros se pueden ver en la documentación: .
Configuración de PostgreSQL
Para que el archivador dentro de la base suba automáticamente los registros WAL a la nube y se recupere de ellos (si es necesario), debe establecer varios parámetros en el archivo de configuración /etc/postgresql/12/main/postgresql.conf. Primero, debe asegurarse, de que ninguna de las configuraciones siguientes esté establecida en otros valores, para que al reiniciar la configuración, el SGBD no se caiga. Estos parámetros se pueden agregar usando:
#!/bin/bash
echo "wal_level=replica" >> /etc/postgresql/12/main/postgresql.conf
echo "archive_mode=on" >> /etc/postgresql/12/main/postgresql.conf
echo "archive_command='/usr/local/bin/wal-g wal-push "%p" >> /var/log/postgresql/archive_command.log 2>&1' " >> /etc/postgresql/12/main/postgresql.conf
echo “archive_timeout=60” >> /etc/postgresql/12/main/postgresql.conf
echo "restore_command='/usr/local/bin/wal-g wal-fetch "%f" "%p" >> /var/log/postgresql/restore_command.log 2>&1' " >> /etc/postgresql/12/main/postgresql.conf
# перезагружаем конфиг через отправку SIGHUP сигнала всем процессам БД
killall -s HUP postgres
Descripción de los parámetros establecidos:
- wal_level – cuánta información escribir en los registros WAL, "replica" – escribir todo;
- archive_mode – habilitación de la carga de registros WAL usando el comando del parámetro archive_command;
- archive_command – comando para archivar el registro WAL completado;
- archive_timeout – la archivación de registros solo ocurre cuando se ha completado, pero si su servidor modifica/agrega pocos datos a la base de datos, tiene sentido establecer un límite en segundos, tras el cual se llamará forzosamente al comando de archivado (tengo una escritura intensa en la base cada segundo, así que decidí no establecer este parámetro en producción.);
- restore_command – comando para restaurar el registro WAL desde la copia de seguridad, se usará en caso de que falten los últimos cambios en la base de datos en la "copia de seguridad completa" (base backup).
Más sobre todos estos parámetros se puede leer en la traducción de la documentación oficial: .
Configuración del programa de copias de seguridad
Sin duda, la forma más conveniente de iniciar es mediante cron. Precisamente eso configuraremos para crear copias de seguridad. Comencemos con el comando para crear una copia de seguridad completa: en wal-g es un argumento de inicio. backup-push. Sin embargo, primero es mejor ejecutar este comando manualmente como el usuario postgres para asegurarnos de que todo está bien (y que no hay errores de acceso):
#!/bin/bash
su - postgres -c '/usr/local/bin/wal-g backup-push /var/lib/postgresql/12/main'
En los argumentos de inicio se especifica la ruta al directorio de datos; recuerdo que se puede conocer ejecutando pg_lsclusters.
Si todo ha salido sin errores y los datos se han cargado en el almacenamiento S3, se puede configurar una ejecución periódica en crontab:
#!/bin/bash
echo "15 4 * * * /usr/local/bin/wal-g backup-push /var/lib/postgresql/12/main >> /var/log/postgresql/walg_backup.log 2>&1" >> /var/spool/cron/crontabs/postgres
# задаем владельца и выставляем правильные права файлу
chown postgres: /var/spool/cron/crontabs/postgres
chmod 600 /var/spool/cron/crontabs/postgres
En este ejemplo, el proceso de copia de seguridad se inicia todos los días a las 4:15 a.m.
Eliminación de copias de seguridad antiguas
Probablemente no necesites almacenar todas las copias de seguridad desde la era mesozoica, por lo que será útil limpiar periódicamente tu almacenamiento (tanto copias de seguridad completas como registros WAL). Haremos esto también a través de una tarea cron:
#!/bin/bash
echo "30 6 * * * /usr/local/bin/wal-g delete before FIND_FULL $(date -d '-10 days' '+%FT%TZ') --confirm >> /var/log/postgresql/walg_delete.log 2>&1" >> /var/spool/cron/crontabs/postgres
# ещё раз задаем владельца и выставляем правильные права файлу (хоть это обычно это и не нужно повторно делать)
chown postgres: /var/spool/cron/crontabs/postgres
chmod 600 /var/spool/cron/crontabs/postgres
Cron ejecutará esta tarea todos los días a las 6:30 a.m., eliminando todo (copias de seguridad completas, deltas y WALs) excepto las copias de los últimos 10 días, pero dejará al menos una copia de la fecha indicada, para que cualquier punto hasta de fecha caiga en PITR. después de No es ningún secreto que la clave para una base de datos saludable es la restauración periódica y la verificación de la integridad de los datos. Cómo restaurar usando WAL-G lo explicaré en esta sección, y hablaremos de las verificaciones después.
Recuperación de la copia de seguridad
Cabe destacar por separado
que para la restauración en un entorno de prueba (todo lo que no sea producción) se debe utilizar una cuenta de Solo Lectura en S3, para no sobrescribir accidentalmente las copias de seguridad. En el caso de WAL-G, es necesario otorgar al usuario S3 los siguientes permisos en la política de grupo ( Effect: Allows3:GetObject): s3:ListBucket, s3:GetBucketLocation, . Y, por supuesto, no olvides establecer previamentearchive_mode=off en el archivo de configuración , para que tu base de datos de prueba no intente hacer una copia de seguridad en silencio. postgresql.confLa restauración se realiza con un simple movimiento de mano eliminando todos los datos de PostgreSQL
incluyendo usuarios, por lo que, por favor, ten mucho cuidado al ejecutar los siguientes comandos. eliminación de todos los datos de PostgreSQL (incluidos los usuarios), por lo tanto, por favor, tenga mucho cuidado al ejecutar los siguientes comandos.
#!/bin/bash
# если есть балансировщик подключений (например, pgbouncer), то вначале отключаем его, чтобы он не нарыгал ошибок в лог
service pgbouncer stop
# если есть демон, который перезапускает упавшие процессы (например, monit), то останавливаем в нём процесс мониторинга базы (у меня это pgsql12)
monit stop pgsql12
# или останавливаем мониторинг полностью
service monit stop
# останавливаем саму базу данных
service postgresql stop
# удаляем все данные из текущей базы (!!!); лучше предварительно сделать их копию, если есть свободное место на диске
rm -rf /var/lib/postgresql/12/main
# скачиваем резервную копию и разархивируем её
su - postgres -c '/usr/local/bin/wal-g backup-fetch /var/lib/postgresql/12/main LATEST'
# помещаем рядом с базой специальный файл-сигнал для восстановления (см. https://postgrespro.ru/docs/postgresql/12/runtime-config-wal#RUNTIME-CONFIG-WAL-ARCHIVE-RECOVERY ), он обязательно должен быть создан от пользователя postgres
su - postgres -c 'touch /var/lib/postgresql/12/main/recovery.signal'
# запускаем базу данных, чтобы она инициировала процесс восстановления
service postgresql start
Para aquellos que desean verificar el proceso de recuperación, a continuación se presenta un pequeño trozo de magia bash, de modo que en caso de problemas durante la recuperación, el script se caiga con un código de salida distinto de cero. En este ejemplo, se realizan 120 comprobaciones con un tiempo de espera de 5 segundos (un total de 10 minutos para la recuperación) para saber si se eliminó el archivo de señal (lo que indicará que la recuperación se realizó con éxito):
#!/bin/bash
CHECK_RECOVERY_SIGNAL_ITER=0
while [ ${CHECK_RECOVERY_SIGNAL_ITER} -le 120 ]
do
if [ ! -f "/var/lib/postgresql/12/main/recovery.signal" ]
then
echo "recovery.signal removed"
break
fi
sleep 5
((CHECK_RECOVERY_SIGNAL_ITER+1))
done
# если после всех проверок файл всё равно существует, то падаем с ошибкой
if [ -f "/var/lib/postgresql/12/main/recovery.signal" ]
then
echo "recovery.signal still exists!"
exit 17
fi
Después de una recuperación exitosa, no olvide reiniciar todos los procesos (pgbouncer/monit, etc.).
Verificación de datos después de la recuperación
Es esencial verificar la integridad de la base de datos después de la recuperación, para evitar situaciones con copias de seguridad dañadas o corruptas. Y es mejor hacerlo con cada archivo de respaldo creado, pero dónde y cómo depende solamente de su imaginación (puede levantar servidores dedicados por horas o ejecutar la verificación en CI). Pero como mínimo, es necesario verificar los datos y los índices en la base de datos.
Para verificar los datos, es suficiente pasarlos a través de un volcado, pero mejor si al crear la base tiene activadas las sumas de verificación ():
#!/bin/bash
if ! su - postgres -c 'pg_dumpall > /dev/null'
then
echo 'pg_dumpall failed'
exit 125
fi
Para la verificación de índices, existe , tomaremos la consulta SQL de él de y alrededor construiremos una pequeña lógica:
#!/bin/bash
# добавляем sql-запрос для проверки в файл во временной директории
cat > /tmp/amcheck.sql << EOF
CREATE EXTENSION IF NOT EXISTS amcheck;
SELECT bt_index_check(c.oid), c.relname, c.relpages
FROM pg_index i
JOIN pg_opclass op ON i.indclass[0] = op.oid
JOIN pg_am am ON op.opcmethod = am.oid
JOIN pg_class c ON i.indexrelid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE am.amname = 'btree'
AND c.relpersistence != 't'
AND i.indisready AND i.indisvalid;
EOF
chown postgres: /tmp/amcheck.sql
# добавляем скрипт для запуска проверок всех доступных баз в кластере
# (обратите внимание что переменные и запуск команд – экранированы)
cat > /tmp/run_amcheck.sh << EOF
for DBNAME in $(su - postgres -c 'psql -q -A -t -c "SELECT datname FROM pg_database WHERE datistemplate = false;" ')
do
echo "Database: ${DBNAME}"
su - postgres -c "psql -f /tmp/amcheck.sql -v 'ON_ERROR_STOP=1' ${DBNAME}" && EXIT_STATUS=$? || EXIT_STATUS=$?
if [ "${EXIT_STATUS}" -ne 0 ]
then
echo "amcheck failed on DB: ${DBNAME}"
exit 125
fi
done
EOF
chmod +x /tmp/run_amcheck.sh
# запускаем скрипт
/tmp/run_amcheck.sh > /tmp/amcheck.log
# для проверки что всё прошло успешно можно проверить exit code или grep’нуть ошибку
if grep 'amcheck failed' "/tmp/amcheck.log"
then
echo 'amcheck failed: '
cat /tmp/amcheck.log
exit 125
fi
Resumiendo
Agradezco a Andrey Borodin por su ayuda en la preparación de la publicación y un agradecimiento especial por su contribución al desarrollo de WAL-G.
Con esto, esta nota ha llegado a su fin. Espero haber transmitido la facilidad de configuración y el enorme potencial para utilizar esta herramienta en su empresa. He escuchado mucho sobre WAL-G, pero nunca encontraba tiempo para sentarme y entenderlo. Después de implementarlo, esta artículo fue el resultado.
Cabe mencionar que WAL-G también puede trabajar con las siguientes bases de datos:
- ;
- ;
- ;
- Y según los commits, se esperan algunas más.
Fuente: habr.com
