WAL-G: copias de seguridade e recuperación de DBMS PostgreSQL

Hai tempo que se sabe que facer copias de seguridade en vertedoiros SQL (usando pg_dump ou pg_dumpall) non é unha boa idea. Para facer unha copia de seguridade do DBMS PostgreSQL, é mellor usar o comando pg_basebackup, que fai unha copia binaria dos rexistros de WAL. Pero cando comeces a estudar todo o proceso de creación dunha copia e restauración, entenderás que tes que escribir polo menos un par de triciclos para que isto funcione e non che cause dor tanto arriba como abaixo. Para aliviar o sufrimento, desenvolveuse WAL-G.

WAL-G é unha ferramenta escrita en Go para facer copias de seguridade e restaurar bases de datos PostgreSQL (e máis recentemente MySQL/MariaDB, MongoDB e FoundationDB). Admite traballar con almacenamento de Amazon S3 (e análogos, por exemplo, Yandex Object Storage), así como Google Cloud Storage, Azure Storage, Swift Object Storage e simplemente co sistema de ficheiros. Toda a configuración redúcese a pasos sinxelos, pero debido ao feito de que os artigos sobre ela están espallados por Internet, non hai un manual completo de instrucións que inclúa todos os pasos do principio ao final (hai varias publicacións sobre Habré, pero alí pérdense moitos puntos).

WAL-G: copias de seguridade e recuperación de DBMS PostgreSQL

Este artigo foi escrito principalmente para sistematizar o meu coñecemento. Non son DBA e podo expresarme nun idioma profano nalgún lugar, así que calquera corrección é benvida.

Por separado, observo que todo a continuación é relevante e probado para PostgreSQL 12.3 en Ubuntu 18.04, todos os comandos deben ser executados como usuario privilexiado.

Instalación

No momento de escribir este artigo, a versión estable de WAL-G é v0.2.15 (marzo de 2020). Isto é o que usaremos (pero se queres construílo vostede mesmo desde a rama mestra, entón o repositorio de github ten todas as instrucións para iso). Para descargar e instalar tes que facer:

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

Despois diso, primeiro debes configurar WAL-G e despois o propio PostgreSQL.

Configurando WAL-G

Como exemplo de almacenamento de copias de seguridade, utilizarase Amazon S3 (porque está máis preto dos meus servidores e o seu uso é moi barato). Para traballar con el, necesitas un "cubo s3" e claves de acceso.

Todos os artigos anteriores sobre WAL-G utilizaron a configuración usando variables de ambiente, pero con esta versión pódese localizar a configuración ficheiro .walg.json no directorio home do usuario de postgres. Para crealo, execute o seguinte 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éixeme explicar un pouco sobre todos os parámetros:

  • WALG_S3_PREFIX – o camiño ao teu depósito S3 onde se cargarán as copias de seguridade (podes na raíz ou nun cartafol);
  • AWS_ACCESS_KEY_ID - clave de acceso en S3 (en caso de recuperación nun servidor de proba, estas chaves deben ter unha política de só lectura. Isto descríbese con máis detalle na sección de recuperación.);
  • AWS_SECRET_ACCESS_KEY - chave secreta no almacenamento S3;
  • WALG_COMPRESSION_METHOD – método de compresión, é mellor usar Brotli (xa que esta é a media dourada entre o tamaño final e a velocidade de compresión/descompresión);
  • WALG_DELTA_MAX_STEPS – o número de "deltas" antes de crear unha copia de seguridade completa (aforran tempo e tamaño dos datos descargados, pero poden retardar lixeiramente o proceso de recuperación, polo que non é recomendable utilizar valores grandes);
  • PGDATA - ruta ao directorio cos datos da súa base de datos (podes averiguarlo executando o comando pg_lsclusters);
  • PGHOST – conectarse á base de datos, cunha copia de seguridade local é mellor facelo a través dun socket Unix como neste exemplo.

Outros parámetros pódense atopar na documentación: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

Configuración de PostgreSQL

Para que o arquivador dentro da base de datos cargue rexistros WAL na nube e os restaure desde eles (se é necesario), cómpre establecer varios parámetros no ficheiro de configuración. /etc/postgresql/12/main/postgresql.conf. Só para comezar tes que asegurarteque ningunha das seguintes opcións está configurada con outros valores, de xeito que cando se recarga a configuración, o DBMS non falla. Podes engadir estes 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

Descrición dos parámetros a configurar:

  • nivel_wal – canta información escribir nos rexistros de WAL, “réplica” – escribir todo;
  • modo_arquivo – habilite a descarga de rexistros WAL usando o comando do parámetro comando_arquivo;
  • comando_arquivo – comando para arquivar un rexistro WAL completado;
  • archive_timeout – o arquivo dos rexistros realízase só cando se completa, pero se o seu servidor cambia/engade poucos datos á base de datos, entón ten sentido establecer aquí un límite en segundos, despois do cal o comando de arquivo chamarase á forza (Escribo intensamente na base de datos cada segundo, polo que decidín non establecer este parámetro na produción);
  • comando_restaurar – utilizarase o comando para restaurar o rexistro WAL a partir dunha copia de seguridade se a "copia de seguridade completa" (copia de seguridade base) carece dos últimos cambios na base de datos.

Podes ler máis sobre todos estes parámetros na tradución da documentación oficial: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Configurar unha programación de copia de seguridade

Diga o que se diga, o xeito máis cómodo de executalo é cron. Isto é o que configuraremos para crear copias de seguridade. Imos comezar co comando para crear unha copia de seguridade completa: en wal-g este é o argumento de inicio backup-push. Pero primeiro, é mellor executar este comando manualmente desde o usuario de postgres para asegurarse de que todo está ben (e non hai erros de acceso):

#!/bin/bash

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

Os argumentos de inicio indican o camiño ao directorio de datos; recórdoche que podes descubrilo executando pg_lsclusters.

Se todo foi sen erros e os datos se cargaron no almacenamento S3, entón podes configurar o lanzamento 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

Neste exemplo, o proceso de copia de seguranza comeza todos os días ás 4:15 da mañá.

Eliminando copias de seguranza antigas

O máis probable é que non necesites gardar absolutamente todas as copias de seguridade da era mesozoica, polo que será útil "limpar" periodicamente o teu almacenamento (tanto "copias de seguranza completas" como rexistros WAL). Farémolo todo a través dunha tarefa 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 executará esta tarefa todos os días ás 6:30 da mañá, eliminando todo (copias de seguranza completas, deltas e WAL) excepto as copias dos últimos 10 días, pero deixando polo menos unha copia de seguridade para data especificada para que calquera punto despois incluíronse datas no PITR.

Restaurando desde unha copia de seguridade

Non é ningún segredo que a clave para unha base de datos saudable é a restauración periódica e a verificación da integridade dos datos no seu interior. Vouche dicir como recuperar usando WAL-G nesta sección e falaremos das comprobacións máis tarde.

Paga a pena sinalar por separado que para restaurar nun ambiente de proba (todo o que non sexa de produción) cómpre utilizar unha conta de só lectura en S3 para non sobrescribir accidentalmente as copias de seguridade. No caso de WAL-G, cómpre configurar os seguintes dereitos para o usuario de S3 na Política de grupo (Efecto: Permitir): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. E, por suposto, non esquezas configurar archive_mode=desactivado no ficheiro de configuración postgresql.conf, para que a súa base de datos de proba non queira facer unha copia de seguranza silenciosa.

A restauración realízase cun leve movemento da man eliminando todos os datos de PostgreSQL (incluídos os usuarios), así que teña moito coidado cando execute os seguintes 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 aqueles que queiran comprobar o proceso de recuperación, preparouse a continuación un pequeno anaco de maxia bash, de xeito que, en caso de problemas na recuperación, o script fallará cun código de saída distinto de cero. Neste exemplo, realízanse 120 comprobacións cun tempo de espera de 5 segundos (un total de 10 minutos para a recuperación) para saber se se eliminou o ficheiro de sinal (isto significará que a recuperación foi 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

Despois da recuperación exitosa, non esqueza iniciar todos os procesos de volta (pgbouncer/monit, etc.).

Comprobando os datos despois da recuperación

É imperativo comprobar a integridade da base de datos despois da restauración, para que non se produza unha situación cunha copia de seguridade rota/torcida. E é mellor facelo con cada arquivo creado, pero onde e como depende só da túa imaxinación (podes crear servidores individuais cada hora ou realizar unha comprobación en CI). Pero, como mínimo, é necesario comprobar os datos e os índices da base de datos.

Para comprobar os datos, abonda con executalos a través dun volcado, pero é mellor que ao crear a base de datos teñas activadas as sumas de verificación (sumas de verificación 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 a consulta sql para iso Probas WAL-G e crea un pouco de lóxica ao redor:

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

Para resumir

Gustaríame expresarlle o meu agradecemento a Andrey Borodin pola súa axuda na preparación da publicación e un agradecemento especial pola súa contribución ao desenvolvemento de WAL-G.

Isto conclúe esta nota. Espero que puiden transmitir a facilidade de configuración e o enorme potencial de usar esta ferramenta na súa empresa. Escoitei moito falar de WAL-G, pero nunca tiven tempo suficiente para sentarme e descubrir. E despois de que o implementei na casa, saíume este artigo.

Por separado, paga a pena notar que WAL-G tamén pode funcionar cos seguintes DBMS:

Fonte: www.habr.com

Engadir un comentario