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

Há muito se sabe que fazer backups em dumps SQL (usando pg_dump ou pg_dumpall) não é uma boa ideia. Para fazer backup do SGBD PostgreSQL, é melhor usar o comando pg_basebackup, que faz uma cópia binária dos logs do WAL. Mas quando você começar a estudar todo o processo de criação e restauração de uma cópia, entenderá que precisa escrever pelo menos alguns triciclos para que tudo funcione e não lhe cause dor acima e abaixo. Para aliviar o sofrimento, foi desenvolvido o WAL-G.

WAL-G é uma ferramenta escrita em Go para fazer backup e restaurar bancos de dados PostgreSQL (e mais recentemente MySQL/MariaDB, MongoDB e FoundationDB). Ele suporta trabalhar com armazenamento Amazon S3 (e análogos, por exemplo, Yandex Object Storage), bem como Google Cloud Storage, Azure Storage, Swift Object Storage e simplesmente com um sistema de arquivos. Toda a configuração se resume a passos simples, mas devido ao fato de artigos sobre o assunto estarem espalhados pela Internet, não existe um manual de instruções completo que inclua todos os passos do início ao fim (há vários posts no Habré, mas muitos pontos são perdidos aí).

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

Este artigo foi escrito principalmente para sistematizar meu conhecimento. Não sou DBA e posso me expressar em linguagem leiga em algum lugar, então qualquer correção é bem-vinda!

Separadamente, observo que tudo abaixo é relevante e testado para PostgreSQL 12.3 no Ubuntu 18.04, todos os comandos devem ser executados como um usuário privilegiado.

Instalação

No momento em que este artigo foi escrito, a versão estável do WAL-G era v0.2.15 (março de 2020). Isso é o que usaremos (mas se você quiser construí-lo sozinho a partir do branch master, o repositório do github tem todas as instruções para isso). Para baixar e instalar você precisa fazer:

#!/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ê precisa primeiro configurar o WAL-G e depois o próprio PostgreSQL.

Configurando WAL-G

Para um exemplo de armazenamento de backups, o Amazon S3 será usado (porque está mais próximo dos meus servidores e seu uso é muito barato). Para trabalhar com ele você precisa de um “balde s3” e chaves de acesso.

Todos os artigos anteriores sobre o WAL-G usaram configuração usando variáveis ​​de ambiente, mas com esta versão as configurações podem ser localizadas em Arquivo .walg.json no diretório inicial 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 – o caminho para o seu bucket S3 onde os backups serão carregados (você pode para a raiz ou para uma pasta);
  • AWS_ACCESS_KEY_ID – chave de acesso no S3 (em caso de recuperação em um servidor de teste, essas chaves devem ter Política ReadOnly! Isto é descrito com mais detalhes na seção sobre recuperação.);
  • AWS_SECRET_ACCESS_KEY – chave secreta no armazenamento S3;
  • WALG_COMPRESSION_METHOD – método de compressão, é melhor usar Brotli (já que este é o meio-termo entre o tamanho final e a velocidade de compressão/descompressão);
  • WALG_DELTA_MAX_STEPS – o número de “deltas” antes de criar um backup completo (economizam tempo e tamanho dos dados baixados, mas podem retardar um pouco o processo de recuperação, por isso não é aconselhável usar valores grandes);
  • PGDATA – caminho para o diretório com os dados do seu banco de dados (você pode descobrir executando o comando pg_lsclusters);
  • PHOST – conectando-se ao banco de dados, com um backup local é melhor fazê-lo através de um soquete unix como neste exemplo.

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

Configurando o PostgreSQL

Para que o arquivador dentro do banco de dados carregue os logs do WAL para a nuvem e os restaure a partir deles (se necessário), você precisa definir vários parâmetros no arquivo de configuração /etc/postgresql/12/main/postgresql.conf. Só para começar você precisa ter certezaque nenhuma das configurações abaixo esteja definida com nenhum outro valor, para que quando a configuração for recarregada, o SGBD não trave. Você pode adicionar esses 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

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

  • nível_wal – quanta informação escrever nos logs WAL, “réplica” – escrever tudo;
  • modo_arquivo – habilitar o download de logs WAL usando o comando do parâmetro comando_arquivo;
  • comando_arquivo – comando para arquivar um log WAL concluído;
  • arquivo_timeout – o arquivamento de logs é realizado somente quando estiver concluído, mas se o seu servidor alterar/adicionar poucos dados ao banco de dados, então faz sentido definir aqui um limite em segundos, após o qual o comando de arquivamento será chamado à força (Eu escrevo intensamente no banco de dados a cada segundo, então decidi não definir esse parâmetro na produção);
  • comando_restauração – o comando para restaurar o log WAL de um backup será utilizado se o “backup completo” (backup base) não possuir as últimas alterações no banco de dados.

Você pode ler mais sobre todos esses parâmetros na tradução da documentação oficial: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Configurando um agendamento de backup

O que quer que se diga, a maneira mais conveniente de executá-lo é o cron. É isso que iremos configurar para criar backups. Vamos começar com o comando para criar um backup completo: no wal-g este é o argumento de lançamento push de backup. Mas primeiro, é melhor executar este comando manualmente a partir do usuário postgres para ter certeza de que está tudo bem (e não há erros de acesso):

#!/bin/bash

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

Os argumentos de inicialização indicam o caminho para o diretório de dados - lembro que você pode descobrir executando pg_lsclusters.

Se tudo correu sem erros e os dados foram carregados no armazenamento S3, você poderá configurar o lançamento periódico 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 começa todos os dias às 4h15.

Excluindo backups antigos

Muito provavelmente, você não precisa manter absolutamente todos os backups da era Mesozóica, por isso será útil “limpar” periodicamente seu armazenamento (tanto “backups completos” quanto logs WAL). Faremos tudo isso por meio 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á esta tarefa todos os dias às 6h30, excluindo tudo (backups completos, deltas e WALs), exceto cópias dos últimos 10 dias, mas deixando pelo menos um backup para data especificada para que qualquer ponto depois as datas foram incluídas no PITR.

Restaurando de um backup

Não é nenhum segredo que a chave para um banco de dados saudável é a restauração periódica e a verificação da integridade dos dados contidos nele. Explicarei como recuperar usando WAL-G nesta seção e falaremos sobre verificações mais tarde.

Separadamente digno de nota que para restaurar em ambiente de teste (tudo que não seja de produção) é necessário usar uma conta Read Only no S3 para não sobrescrever acidentalmente os backups. No caso do WAL-G, você precisa definir os seguintes direitos para o usuário S3 na Política de Grupo (Efeito: Permitir): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. E, claro, não se esqueça de definir modo_arquivo=desligado no arquivo de configurações postgresql.conf, para que seu banco de dados de teste não queira fazer backup silenciosamente.

A restauração é realizada com um leve movimento da mão excluindo todos os dados do PostgreSQL (incluindo usuários), portanto, seja extremamente cuidadoso ao executar os comandos a seguir.

#!/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 quem deseja verificar o processo de recuperação, um pequeno pedaço de magia do bash foi preparado abaixo, para que em caso de problemas na recuperação, o script trave com um código de saída diferente de zero. Neste exemplo, são feitas 120 verificações com um tempo limite de 5 segundos (um total de 10 minutos para recuperação) para descobrir se o arquivo de sinal foi excluído (isso significará 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 a recuperação bem-sucedida, não se esqueça de reiniciar todos os processos (pgbouncer/monit, etc.).

Verificando dados após a recuperação

É imprescindível verificar a integridade do banco de dados após a restauração, para que não surja uma situação de backup quebrado/torto. E é melhor fazer isso com cada arquivo criado, mas onde e como depende apenas da sua imaginação (você pode aumentar servidores individuais de hora em hora ou executar uma verificação no CI). Mas, no mínimo, é necessário verificar os dados e índices do banco de dados.

Para verificar os dados, basta executá-los através de um dump, mas é melhor que ao criar o banco de dados você tenha os checksums habilitados (somas de verificação de dados):

#!/bin/bash

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

Para verificar índices - existe módulo amcheck, vamos pegar a consulta sql para ele Testes WAL-G e construa um pouco de lógica em torno disso:

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

Gostaria de expressar minha gratidão a Andrey Borodin pela ajuda na preparação da publicação e um agradecimento especial por sua contribuição para o desenvolvimento do WAL-G!

Isto conclui esta nota. Espero ter conseguido transmitir a facilidade de configuração e o enorme potencial de utilização desta ferramenta na sua empresa. Ouvi muito sobre o WAL-G, mas nunca tive tempo suficiente para sentar e descobrir. E depois que implementei em casa, este artigo saiu de mim.

Separadamente, vale ressaltar que o WAL-G também pode funcionar com os seguintes SGBDs:

Fonte: habr.com

Adicionar um comentário