WAL-G: backup e ripristino di DBMS PostgreSQL

È noto da tempo che eseguire backup in dump SQL (utilizzando pg_dump o pg_dumpall) non è una buona idea. Per eseguire il backup del DBMS PostgreSQL, è meglio utilizzare il comando pg_basebackup, che crea una copia binaria dei log WAL. Ma quando inizi a studiare l'intero processo di creazione di una copia e ripristino, capirai che devi scrivere almeno un paio di tricicli affinché funzioni e non ti causi dolore sia sopra che sotto. Per alleviare la sofferenza è stato sviluppato WAL-G.

WAL-G è uno strumento scritto in Go per il backup e il ripristino dei database PostgreSQL (e più recentemente MySQL/MariaDB, MongoDB e FoundationDB). Supporta il lavoro con lo storage Amazon S3 (e analoghi, ad esempio, Yandex Object Storage), nonché Google Cloud Storage, Azure Storage, Swift Object Storage e semplicemente con il file system. L'intera configurazione si riduce a semplici passaggi, ma a causa del fatto che gli articoli a riguardo sono sparsi su Internet, non esiste un manuale completo che includa tutti i passaggi dall'inizio alla fine (ci sono diversi post su Habré, ma qui mancano molti punti).

WAL-G: backup e ripristino di DBMS PostgreSQL

Questo articolo è stato scritto principalmente per sistematizzare le mie conoscenze. Non sono un DBA e posso esprimermi da qualche parte in un linguaggio profano, quindi qualsiasi correzione è benvenuta!

Separatamente, noto che tutto ciò che segue è rilevante e testato per PostgreSQL 12.3 su Ubuntu 18.04, tutti i comandi devono essere eseguiti come utente privilegiato.

Installazione

Al momento della stesura di questo articolo, la versione stabile di WAL-G è v0.2.15 (marzo 2020). Questo è ciò che useremo (ma se vuoi crearlo tu stesso dal ramo master, il repository github contiene tutte le istruzioni per farlo). Per scaricare e installare è necessario fare:

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

Successivamente, è necessario configurare prima WAL-G e poi PostgreSQL stesso.

Configurazione di WAL-G

Per un esempio di archiviazione dei backup, verrà utilizzato Amazon S3 (perché è più vicino ai miei server e il suo utilizzo è molto economico). Per lavorare con esso, hai bisogno di un "bucket s3" e di chiavi di accesso.

Tutti gli articoli precedenti su WAL-G utilizzavano la configurazione utilizzando variabili di ambiente, ma con questa versione è possibile individuare le impostazioni File .walg.json nella directory home dell'utente postgres. Per crearlo, esegui il seguente 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

Lasciatemi spiegare un po' tutti i parametri:

  • WALG_S3_PREFIX – il percorso del tuo bucket S3 in cui verranno caricati i backup (puoi farlo nella root o in una cartella);
  • AWS_ACCESS_KEY_ID – chiave di accesso in S3 (in caso di ripristino su un server di test, queste chiavi devono avere policy di sola lettura! Questo è descritto più dettagliatamente nella sezione sul recupero.);
  • AWS_SECRET_ACCESS_KEY – chiave segreta nello storage S3;
  • WALG_COMPRESSION_METHOD – metodo di compressione, è meglio usare Brotli (poiché questa è la via di mezzo tra la dimensione finale e la velocità di compressione/decompressione);
  • WALG_DELTA_MAX_STEPS – il numero di “delta” prima di creare un backup completo (fanno risparmiare tempo e dimensione dei dati scaricati, ma possono rallentare leggermente il processo di ripristino, quindi non è consigliabile utilizzare valori grandi);
  • PGDATA – percorso della directory con i dati del database (puoi scoprirlo eseguendo il comando pg_lsclusters);
  • PGHOST – connettersi al database, con un backup locale è meglio farlo tramite unix-socket come in questo esempio.

Altri parametri possono essere trovati nella documentazione: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

Configurazione di PostgreSQL

Affinché l'archiviatore all'interno del database possa caricare i registri WAL nel cloud e ripristinarli da essi (se necessario), è necessario impostare diversi parametri nel file di configurazione /etc/postgresql/12/main/postgresql.conf. Solo per cominciare devi assicurarteneche nessuna delle impostazioni seguenti sia impostata su altri valori, in modo che quando la configurazione viene ricaricata, il DBMS non si blocca. Puoi aggiungere questi parametri 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

Descrizione dei parametri da impostare:

  • livello_wal – quante informazioni scrivere nei log WAL, “replica” – scrivere tutto;
  • modalità_archivio – abilitare il download dei log WAL utilizzando il comando dal parametro archivio_comando;
  • archivio_comando – comando per l'archiviazione di un registro WAL completato;
  • archivio_timeout – l'archiviazione dei log viene eseguita solo quando è completata, ma se il tuo server cambia/aggiunge pochi dati al database, allora ha senso impostare qui un limite in secondi, dopo il quale il comando di archiviazione verrà chiamato forzatamente (Scrivo intensamente nel database ogni secondo, quindi ho deciso di non impostare questo parametro in produzione);
  • comando_ripristina – il comando per ripristinare il log WAL da un backup verrà utilizzato se nel “backup completo” (backup di base) mancano le ultime modifiche nel database.

Puoi leggere di più su tutti questi parametri nella traduzione della documentazione ufficiale: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Impostazione di una pianificazione di backup

Qualunque cosa si possa dire, il modo più conveniente per eseguirlo è cron. Questo è ciò che configureremo per creare backup. Cominciamo con il comando per creare un backup completo: in wal-g questo è l'argomento di lancio spinta di backup. Ma prima, è meglio eseguire questo comando manualmente dall'utente postgres per assicurarsi che tutto vada bene (e che non ci siano errori di accesso):

#!/bin/bash

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

Gli argomenti di lancio indicano il percorso della directory dei dati: ti ricordo che puoi scoprirlo eseguendo pg_lsclusters.

Se tutto è andato senza errori e i dati sono stati caricati nello storage S3, puoi configurare l'avvio periodico in 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

In questo esempio, il processo di backup inizia ogni giorno alle 4:15.

Eliminazione dei vecchi backup

Molto probabilmente, non è necessario conservare assolutamente tutti i backup dell'era mesozoica, quindi sarà utile “ripulire” periodicamente il proprio spazio di archiviazione (sia “backup completi” che registri WAL). Faremo tutto questo attraverso un'attività 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 eseguirà questa attività ogni giorno alle 6:30, eliminando tutto (backup completi, delta e WAL) tranne le copie degli ultimi 10 giorni, ma lasciando almeno un backup a data specificata in modo che qualsiasi punto dopo le date sono state incluse nel PITR.

Ripristino da un backup

Non è un segreto che la chiave per un database sano sia il ripristino periodico e la verifica dell'integrità dei dati al suo interno. Ti dirò come ripristinare utilizzando WAL-G in questa sezione e parleremo dei controlli più tardi.

Separatamente degno di nota che per ripristinare in ambiente di test (tutto ciò che non è produzione) è necessario utilizzare un account di sola lettura in S3 per non sovrascrivere accidentalmente i backup. Nel caso di WAL-G, è necessario impostare i seguenti diritti per l'utente S3 in Criteri di gruppo (Effetto: Consenti): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. E, naturalmente, non dimenticare di impostare modalità_archivio=disattiva nel file delle impostazioni postgresql.conf, in modo che il database di test non voglia essere sottoposto a backup in silenzio.

Il restauro viene eseguito con un leggero movimento della mano eliminando tutti i dati PostgreSQL (inclusi gli utenti), quindi fai molta attenzione quando esegui i seguenti comandi.

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

Per coloro che vogliono controllare il processo di ripristino, di seguito è stata preparata una piccola magia di bash, in modo che in caso di problemi nel ripristino, lo script andrà in crash con un codice di uscita diverso da zero. In questo esempio vengono effettuati 120 controlli con un timeout di 5 secondi (totale 10 minuti per il ripristino) per verificare se il file di segnale è stato cancellato (questo vorrà dire che il ripristino è andato a buon fine):

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

Dopo aver eseguito con successo il ripristino, non dimenticare di riavviare tutti i processi (pgbouncer/monit, ecc.).

Controllo dei dati dopo il ripristino

È fondamentale verificare l'integrità del database dopo il ripristino, in modo che non si verifichi una situazione con un backup danneggiato/storto. Ed è meglio farlo con ogni archivio creato, ma dove e come dipende solo dalla tua immaginazione (puoi aumentare i singoli server su base oraria o eseguire un controllo in CI). Ma come minimo è necessario controllare i dati e gli indici nel database.

Per verificare i dati è sufficiente eseguirli tramite un dump, ma è meglio che durante la creazione del database si abbiano abilitati i checksum (checksum dei dati):

#!/bin/bash

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

Per controllare gli indici - esiste modulo amcheck, prendiamo la query sql da Test WAL-G e costruisci un po' di logica attorno ad esso:

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

riassumendo

Vorrei esprimere la mia gratitudine ad Andrey Borodin per il suo aiuto nella preparazione della pubblicazione e un ringraziamento speciale per il suo contributo allo sviluppo di WAL-G!

Ciò conclude questa nota. Spero di essere riuscito a trasmettere la facilità di configurazione e l'enorme potenziale di utilizzo di questo strumento nella tua azienda. Ho sentito molto parlare di WAL-G, ma non ho mai avuto abbastanza tempo per sedermi e capirlo. E dopo averlo implementato a casa, mi è uscito questo articolo.

Separatamente, vale la pena notare che WAL-G può funzionare anche con i seguenti DBMS:

Fonte: habr.com

Aggiungi un commento