WAL-G: backups e recuperação de bancos de dados PostgreSQL

Já é bem conhecido que fazer backups em dumps SQL (usando pg_dump ou pg_dumpall) – não é uma boa ideia. Para fazer backup de bancos de dados PostgreSQL, é melhor usar o comando pg_basebackup, que cria uma cópia binária dos logs WAL. Mas quando você começa a estudar todo o processo de cópia e recuperação, percebe que precisa construir pelo menos algumas bicicletas de três rodas para que tudo funcione corretamente e não cause dor tanto por cima quanto por baixo. Para aliviar esse sofrimento, foi desenvolvido o WAL-G.

WAL-G – é uma ferramenta escrita em Go para backup e recuperação de bancos de dados PostgreSQL (e, desde recentemente, também MySQL/MariaDB, MongoDB e FoundationDB). Ela suporta funcionamento com repositórios Amazon S3 (e análogos, como Yandex Object Storage), bem como Google Cloud Storage, Azure Storage, Swift Object Storage e simplesmente com o sistema de arquivos. Toda a configuração se resume a passos simples, mas devido ao fato de que os artigos sobre isso estão espalhados pela internet – não há um manual completo que inclua todos os passos de A a Z (no Habr há algumas postagens, mas muitos pontos são omitidos).

WAL-G: backups e recuperação de bancos de dados PostgreSQL

Este artigo foi escrito principalmente para sistematizar meu conhecimento. Não sou DBA e, em alguns momentos, posso me expressar em uma linguagem mais casual de desenvolvedor, portanto, correções são bem-vindas!

Vale ressaltar que tudo o que se segue é relevante e testado para PostgreSQL 12.3 no Ubuntu 18.04; todos os comandos devem ser executados a partir de um usuário privilegiado.

Instalação

No momento da redação deste artigo, a versão estável do WAL-G é v0.2.15 (março de 2020). É essa versão que usaremos (mas se você quiser compilá-lo sozinho a partir do branch master, há todas as instruções no repositório do GitHub). Para download e instalação, você deve executar:

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

Depois disso, você deve primeiro configurar o WAL-G e depois o próprio PostgreSQL.

Configuração do WAL-G

Para o exemplo de armazenamento de backups, usaremos o Amazon S3 (porque está mais perto dos meus servidores e seu uso é muito barato). Para trabalhar com ele, você precisa de um "bucket S3" e chaves de acesso.

Em todos os artigos anteriores sobre o WAL-G, a configuração foi feita usando variáveis de ambiente, mas a partir desta versão, as configurações podem ser colocadas em .walg.json arquivo na diretório home do usuário postgres. Para criá-lo, 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

Deixe-me explicar um pouco sobre todos os parâmetros:

  • WALG_S3_PREFIX – caminho para seu bucket S3 onde os backups serão carregados (pode ser tanto na raiz quanto em uma pasta);
  • AWS_ACCESS_KEY_ID – chave de acesso do S3 (em caso de recuperação em um servidor de teste – essas chaves devem ter a política ReadOnly! Isso está mais detalhado na seção sobre recuperação);
  • AWS_SECRET_ACCESS_KEY – chave secreta no armazenamento S3;
  • WALG_COMPRESSION_METHOD – método de compressão, recomenda-se usar Brotli (pois é um meio-termo entre o tamanho final e a velocidade de compressão/descompressão);
  • WALG_DELTA_MAX_STEPS – número de "deltas" antes da criação de um backup completo (eles economizam tempo e tamanho de dados a serem carregados, mas podem desacelerar o processo de recuperação, portanto, não se recomenda usar valores altos);
  • PGDATA – caminho para o diretório com os dados do seu banco (pode ser obtido executando o comando pg_lsclusters);
  • PGHOST – conexão com o banco, em backups locais é melhor fazer através de unix-socket como neste exemplo.

Os outros parâmetros podem ser vistos na documentação: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

Configuração do PostgreSQL

Para que o arquivador dentro do banco faça o upload dos registros WAL na nuvem e se recupere deles (caso necessário) – é preciso definir alguns parâmetros no arquivo de configuração /etc/postgresql/12/main/postgresql.conf. Mas primeiro você precisa garantir, que nenhuma das configurações abaixo foi definida como outros valores, para que, ao reiniciar a configuração – o SGBD não caia. Esses parâmetros podem ser adicionados com:

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

Descrição dos parâmetros a serem configurados:

  • wal_level – quanta informação escrever nos registros WAL, "replica" – escrever tudo;
  • archive_mode – habilitação do upload dos registros WAL usando o comando do parâmetro archive_command;
  • archive_command – comando para arquivar o registro WAL concluído;
  • archive_timeout – a arquivação dos registros só ocorre quando está concluído, mas se seu servidor modifica/adiciona poucos dados no banco, pode ser útil definir um limite em segundos, após os quais o comando de arquivamento será chamado forçadamente (eu tenho gravação intensa no banco a cada segundo, portanto, optei por não configurar esse parâmetro em produção);
  • restore_command – comando para restaurar o registro WAL de um backup, será utilizado caso as últimas alterações no banco estejam faltando no "backup completo" (base backup).

Mais detalhes sobre todos esses parâmetros podem ser lidos na tradução da documentação oficial: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Configuração da programação de backup

De qualquer forma, o método mais conveniente para iniciar é o cron. É ele que vamos configurar para criar backups. Vamos começar com o comando para criar um backup completo: no wal-g, esse é o argumento de execução. backup-push. Mas primeiro, é melhor executar esse comando manualmente como o usuário postgres, para garantir que tudo está funcionando corretamente (e que não há erros de acesso):

#!/bin/bash

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

Nos argumentos de execução, o caminho para o diretório de dados está especificado – lembrando que você pode descobrir isso executando pg_lsclusters.

Se tudo correu sem erros e os dados foram carregados no armazenamento S3, então você pode configurar a execução periódica no 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 processo de backup é iniciado todos os dias às 4:15 da manhã.

Remoção de backups antigos

Provavelmente, você não precisa manter todos os backups desde a era mesozoica, portanto, será útil periodicamente "limpar" o seu armazenamento (tanto "backups completos" quanto arquivos WAL). Faremos isso também através de uma 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

O cron executará essa tarefa todos os dias às 6:30 da manhã, removendo tudo (backups completos, deltas e WALs) exceto cópias dos últimos 10 dias, mas manterá pelo menos um backup da data indicada, para que qualquer ponto até de data entre em PITR. após Restauração de um backup

Não é segredo para ninguém que a chave de um banco de dados saudável é a restauração e verificação periódica da integridade dos dados internos. Como restaurar usando o WAL-G – falarei nesta seção, e sobre as verificações conversaremos depois.

Vale a pena notar separadamente

que para a restauração em um ambiente de teste (tudo o que não é produção) – é necessário usar uma conta Read Only no S3, para não sobrescrever acidentalmente os backups. No caso do WAL-G, o usuário S3 deve ter as seguintes permissões na Política de Grupo ( Efeito: Permitirs3:GetObject): s3:ListBucket, s3:GetBucketLocation, . E, claro, não se esqueça de ajustar previamentearchive_mode=off no arquivo de configuração , para que seu banco de dados de teste não tentasse fazer um backup em silêncio. postgresql.confA restauração é feita com um simples movimento de mão com

a remoção de todos os dados do PostgreSQL (inclusive usuários), portanto, por favor, seja extremamente cauteloso ao executar os próximos comandos. (incluindo usuários), portanto, por favor, seja extremamente cauteloso ao executar 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 desejam verificar o processo de recuperação — abaixo está um pequeno trecho de mágica bash, para que, em caso de problemas na recuperação, o script falhe com um código de saída diferente de zero. Neste exemplo, são realizadas 120 verificações com um tempo limite de 5 segundos (totalizando 10 minutos para a recuperação), para descobrir se o arquivo sinalizador foi removido (o que indicará que a recuperação foi bem-sucedida):

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

Após uma recuperação bem-sucedida, não se esqueça de reiniciar todos os processos (pgbouncer/monit etc.).

Verificação de dados após a recuperação

É essencial verificar a integridade do banco de dados após a recuperação, para evitar situações com cópias de segurança corrompidas/erradas. E é melhor fazer isso com cada arquivo de backup criado, mas onde e como – depende apenas da sua imaginação (pode-se levantar servidores separados por pagamento por hora ou executar a verificação em CI). Mas, no mínimo – é necessário verificar os dados e os índices no banco de dados.

Para verificar os dados, basta passá-los por um dump, mas é melhor que, ao criar o banco, você tenha as somas de verificação ativadas (data checksums):

#!/bin/bash

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

Para verificação de índices – existe o módulo amcheck, a consulta SQL nele será retirada de testes do WAL-G e em torno disso construiremos uma pequena 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

Resumindo

Agradeço a Andrei Borodin pela ajuda na preparação da publicação e um agradecimento especial pela sua contribuição no desenvolvimento do WAL-G!

Com isso, esta nota chega ao fim. Espero que consegui transmitir a facilidade de configuração e o enorme potencial de aplicação desta ferramenta em sua empresa. Ouvi muito sobre o WAL-G, mas nunca tive tempo para sentar e entender. E após implementá-lo em meu ambiente – saiu este artigo.

Vale ressaltar que o WAL-G também pode trabalhar com os seguintes SGBDs:

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster