WAL-G: copias de seguridad y recuperación de DBMS PostgreSQL

Se sabe desde hace mucho tiempo que realizar copias de seguridad en volcados de SQL (utilizando pg_dump o pg_dumpall) no es una buena idea. Para hacer una copia de seguridad del DBMS PostgreSQL, es mejor usar el comando pg_basebackup, que realiza una copia binaria de los registros WAL. Pero cuando comiences a estudiar todo el proceso de creación de una copia y restauración, comprenderás que necesitas escribir al menos un par de triciclos para que esto funcione y no te cause dolor tanto arriba como abajo. Para aliviar el sufrimiento, se desarrolló WAL-G.

WAL-G es una herramienta escrita en Go para realizar copias de seguridad y restaurar bases de datos PostgreSQL (y más recientemente MySQL/MariaDB, MongoDB y FoundationDB). Admite trabajar con el almacenamiento Amazon S3 (y análogos, por ejemplo, Yandex Object Storage), así como con 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 al hecho de que los artículos al respecto se encuentran dispersos en Internet, no existe un manual completo que incluya todos los pasos de principio a fin (hay varias publicaciones sobre Habré, pero allí se pasan por alto muchos puntos).

WAL-G: copias de seguridad y recuperación de DBMS PostgreSQL

Este artículo fue escrito principalmente para sistematizar mis conocimientos. No soy un DBA y puedo expresarme en un lenguaje sencillo en algún lugar, por lo que cualquier corrección es bienvenida.

Por otra parte, observo que todo lo que aparece a continuación es relevante y está probado para PostgreSQL 12.3 en Ubuntu 18.04, todos los comandos deben ejecutarse como un usuario privilegiado.

Instalación

Al momento de escribir este artículo, la versión estable de WAL-G es v0.2.15 (marzo de 2020). Esto es lo que usaremos (pero si desea compilarlo usted mismo desde la rama maestra, entonces el repositorio de github tiene todas las instrucciones para esto.). Para descargar e instalar necesitas hacer:

#!/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 debe configurar WAL-G y luego el propio PostgreSQL.

Configurar WAL-G

Como ejemplo de almacenamiento de copias de seguridad, se utilizará Amazon S3 (porque está más cerca de mis servidores y su uso es muy económico). Para trabajar con él, necesita un "depósito s3" y claves de acceso.

Todos los artículos anteriores sobre WAL-G usaban configuración usando variables de entorno, pero con esta versión la configuración se puede ubicar en Archivo .walg.json en el directorio de inicio del usuario de postgres. Para crearlo, ejecute 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

Déjame explicarte un poco sobre todos los parámetros:

  • WALG_S3_PREFIX – la ruta a su depósito S3 donde se cargarán las copias de seguridad (puede hacerlo en la raíz o en una carpeta);
  • AWS_ACCESS_KEY_ID – clave de acceso en S3 (En caso de recuperación en un servidor de prueba, ¡estas claves deben tener una política de solo lectura! Esto se describe con más detalle en la sección sobre recuperació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 este es el punto medio entre el tamaño final y la velocidad de compresión/descompresión);
  • WALG_DELTA_MAX_STEPS – el número de “deltas” antes de crear una copia de seguridad completa (ahorran tiempo y tamaño de los datos descargados, pero pueden ralentizar ligeramente el proceso de recuperación, por lo que no es aconsejable utilizar valores grandes);
  • DATOSPG – ruta al directorio con los datos de su base de datos (puedes averiguarlo ejecutando el comando pg_lsclusters);
  • PHOST – conectarse a la base de datos, con una copia de seguridad local es mejor hacerlo a través de un socket Unix como en este ejemplo.

Otros parámetros se pueden encontrar en la documentación: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

Configuración de PostgreSQL

Para que el archivador dentro de la base de datos cargue registros WAL en la nube y los restaure desde ellos (si es necesario), debe configurar varios parámetros en el archivo de configuración. /etc/postgresql/12/main/postgresql.conf. Sólo para empezar necesitas asegurarteque ninguna de las configuraciones siguientes esté establecida en ningún otro valor, de modo que cuando se vuelva a cargar la configuración, el DBMS no falle. Puede agregar estos parámetros 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 a configurar:

  • nivel_wal – cuánta información escribir en los registros WAL, “réplica” – escribir todo;
  • modo_archivo – habilitar la descarga de registros WAL usando el comando del parámetro comando_archivo;
  • comando_archivo – comando para archivar un registro WAL completo;
  • tiempo de espera de archivo – el archivo de registros se realiza solo cuando se completa, pero si su servidor cambia/agrega pocos datos a la base de datos, entonces tiene sentido establecer aquí un límite en segundos, después del cual el comando de archivo se llamará a la fuerza (Escribo intensamente en la base de datos cada segundo, así que decidí no configurar este parámetro en producción.);
  • restaurar_comando – el comando para restaurar el registro WAL desde una copia de seguridad se utilizará si la “copia de seguridad completa” (copia de seguridad base) carece de los últimos cambios en la base de datos.

Puedes leer más sobre todos estos parámetros en la traducción de la documentación oficial: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Configurar un cronograma de respaldo

Digan lo que digan, la forma más conveniente de ejecutarlo es cron. Esto es lo que configuraremos para crear copias de seguridad. Comencemos con el comando para crear una copia de seguridad completa: en wal-g este es el argumento de inicio empuje de respaldo. Pero primero, es mejor ejecutar este comando manualmente desde el usuario de postgres para asegurarnos de que todo esté bien (y que no haya errores de acceso):

#!/bin/bash

su - postgres -c '/usr/local/bin/wal-g backup-push /var/lib/postgresql/12/main'

Los argumentos de inicio indican la ruta al directorio de datos; te recuerdo que puedes averiguarlo ejecutando pg_lsclusters.

Si todo salió sin errores y los datos se cargaron en el almacenamiento S3, entonces puede configurar el inicio periódico 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 comienza todos los días a las 4:15 a. m.

Eliminar copias de seguridad antiguas

Lo más probable es que no necesite conservar absolutamente todas las copias de seguridad de la era Mesozoica, por lo que será útil "limpiar" periódicamente su almacenamiento (tanto las "copias de seguridad completas" como los registros WAL). Haremos todo esto 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 WAL) excepto las copias de los últimos 10 días, pero dejando al menos una copia de seguridad. a fecha especificada para que cualquier punto después las fechas se incluyeron en PITR.

Restaurar desde una copia de seguridad

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 que contiene. Le diré cómo recuperarse usando WAL-G en esta sección y hablaremos sobre las comprobaciones más adelante.

Por separado digno de mención que para restaurar en un entorno de prueba (todo lo que no sea de producción) es necesario utilizar una cuenta de Sólo Lectura en S3 para no sobrescribir accidentalmente las copias de seguridad. En el caso de WAL-G, debe configurar los siguientes derechos para el usuario de S3 en la Política de grupo (Efecto: Permitir): s3:ObtenerObjeto, s3: ListBucket, s3: Obtener ubicación del depósito. Y, por supuesto, no olvides configurar modo_archivo=desactivado en el archivo de configuración postgresql.conf, para que su base de datos de prueba no desee realizar una copia de seguridad en silencio.

La restauración se realiza con un ligero movimiento de la mano. eliminar todos los datos de PostgreSQL (incluidos los usuarios), así que 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 quieran comprobar el proceso de recuperación, a continuación se ha preparado una pequeña pieza de magia bash, de modo que en caso de problemas en la recuperación, el script se bloqueará 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 el archivo de señal se eliminó (esto significará que la recuperación fue exitosa):

#!/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.).

Comprobación de datos después de la recuperación

Es imperativo verificar la integridad de la base de datos después de la restauración, para que no surja una situación con una copia de seguridad rota o torcida. Y es mejor hacer esto con cada archivo creado, pero dónde y cómo depende solo de su imaginación (puede activar servidores individuales cada hora o realizar una verificación en CI). Pero como mínimo, es necesario comprobar los datos y los índices de la base de datos.

Para comprobar los datos basta con ejecutarlos mediante un dump, pero es mejor que al crear la base de datos tengas habilitadas las sumas de comprobación (sumas de control de datos):

#!/bin/bash

if ! su - postgres -c 'pg_dumpall > /dev/null'
then
    echo 'pg_dumpall failed'
    exit 125
fi

Para comprobar índices - existe módulo amcheck, tomemos la consulta SQL de Pruebas WAL-G y construir un poco de lógica a su alrededor:

#!/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

¡Me gustaría expresar mi agradecimiento 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 concluye esta nota. Espero haber podido transmitir la facilidad de configuración y el enorme potencial de utilizar esta herramienta en su empresa. Escuché mucho sobre WAL-G, pero nunca tuve tiempo suficiente para sentarme y resolverlo. Y después de implementarlo en casa, me salió este artículo.

Por otra parte, cabe señalar que WAL-G también puede funcionar con los siguientes DBMS:

Fuente: habr.com

Añadir un comentario