È già noto da tempo che effettuare backup in SQL dump (utilizzando pg_dump o pg_dumpall) non è la migliore delle idee. Per il backup del database 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 di ripristino, capisci che è necessario scrivere almeno un paio di biciclette a tre ruote affinché tutto funzioni e non ti faccia male sia sopra che sotto. Per alleviare le sofferenze, è stato sviluppato WAL-G.
è uno strumento scritto in Go per il backup e il ripristino dei database PostgreSQL (e da poco anche MySQL/MariaDB, MongoDB e FoundationDB). Supporta l'utilizzo con i depositi Amazon S3 (e simili, ad esempio, Yandex Object Storage), oltre a Google Cloud Storage, Azure Storage, Swift Object Storage e semplicemente con il file system. Tutta la configurazione si riduce a semplici passaggi, ma poiché gli articoli su di esso sono sparsi su Internet, non esiste un manuale completo che includa tutti i passaggi da A a Z (su Habr ci sono alcuni post, ma molti aspetti sono tralasciati).

Questo articolo è scritto principalmente per sistematizzare le mie conoscenze. Non sono un DBA e a volte potrei esprimermi in modo colloquiale-sviluppatore, quindi sono benvenuti eventuali miglioramenti!
Voglio sottolineare che tutto quanto segue è pertinente e verificato per PostgreSQL 12.3 su Ubuntu 18.04, tutti i comandi devono essere eseguiti da un utente privilegiato.
Installazione
Al momento della scrittura di questo articolo, la versione stabile di WAL-G è . Questa la useremo (ma se desideri costruirla da solo dal branch master, nel repository su github ci sono tutte le istruzioni per farlo). Per il download e l'installazione, è necessario eseguire:
#!/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/
Dopo di che è necessario configurare prima WAL-G e poi PostgreSQL stesso.
Configurazione di WAL-G
Per esempio, per la memorizzazione dei backup sarà utilizzato Amazon S3 (perché è più vicino ai miei server e il suo utilizzo è molto economico). Per lavorare con esso è necessario un 'bucket S3' e le chiavi di accesso.
In tutti gli articoli precedenti su WAL-G si utilizzava la configurazione tramite variabili d'ambiente, ma a partire da questo rilascio le impostazioni possono essere collocate in nella home directory dell'utente postgres. Per crearlo, eseguiamo 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
Fornirò alcune spiegazioni sui vari parametri:
- WALG_S3_PREFIX – il percorso verso il tuo bucket S3 dove verranno caricati i backup (può essere sia nella radice che in una cartella);
- AWS_ACCESS_KEY_ID – chiave di accesso per S3 (in caso di ripristino su un server di test, queste chiavi devono avere una Policy di sola lettura! È spiegato in dettaglio nella sezione sul ripristino);
- AWS_SECRET_ACCESS_KEY – chiave segreta nello storage S3;
- WALG_COMPRESSION_METHOD – metodo di compressione, è consigliabile utilizzare Brotli (poiché rappresenta un buon compromesso tra dimensione finale e velocità di compressione/decompressione);
- WALG_DELTA_MAX_STEPS – numero di "deltas" prima di creare un backup completo (consentono di risparmiare tempo e spazio sui dati caricati, ma possono rallentare leggermente il processo di ripristino, quindi non è consigliabile utilizzare valori elevati);
- PGDATA – percorso verso la directory contenente i dati del tuo database (può essere scoperto eseguendo il comando pg_lsclusters);
- PGHOST – connessione al database, per i backup locali è meglio effettuare tramite unix-socket come in questo esempio.
Puoi visualizzare gli altri parametri nella documentazione: .
Configurazione di PostgreSQL
Affinché l'archiviatore all'interno del database carichi automaticamente i log WAL nel cloud e possa ripristinarsi da essi (se necessario), è necessario impostare alcuni parametri nel file di configurazione /etc/postgresql/12/main/postgresql.conf. Ma prima di tutto devi assicurarti, che nessuno dei seguenti parametri sia impostato su valori diversi, affinché, al riavvio della configurazione, il DBMS non si blocchi. Questi parametri possono essere aggiunti tramite:
#!/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 impostati:
- wal_level – quante informazioni scrivere nei log WAL, "replica" – scrivere tutto;
- archive_mode – attivazione del caricamento dei log WAL utilizzando il comando del parametro archive_command;
- archive_command – comando per archiviare il WAL-log completato;
- archive_timeout – l'archiviazione dei log avviene solo quando è completata, ma se il tuo server modifica/aggiunge pochi dati al DB, è utile impostare qui un limite in secondi, oltre il quale il comando di archiviazione verrà invocato forzatamente (ho registrazioni intense nel database ogni secondo, quindi ho deciso di non impostare questo parametro in produzione);
- restore_command – comando per ripristinare il WAL-log dal backup, verrà utilizzato nel caso in cui nel "backup completo" (base backup) manchino le ultime modifiche nel DB.
Maggiore informazioni su tutti questi parametri possono essere lette nella traduzione della documentazione ufficiale: .
Configurazione del programma di backup
Non ci sono dubbi che il modo più comodo per avviare è cron. È proprio questo che configureremo per creare i backup. Iniziamo con il comando per creare un backup completo: in wal-g questo è l'argomento di avvio backup-push. Ma per cominciare è meglio eseguire questo comando manualmente dall'utente postgres, per assicurarsi che tutto vada bene (e non ci siano errori di accesso):
#!/bin/bash
su - postgres -c '/usr/local/bin/wal-g backup-push /var/lib/postgresql/12/main'
Negli argomenti di avvio è specificato il percorso della directory contenente i dati: ricordo che può essere scoperto eseguendo pg_lsclusters.
Se tutto è andato senza errori e i dati sono stati caricati nello storage S3, si può quindi 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 viene avviato ogni giorno alle 4:15 del mattino.
Eliminazione di backup obsoleti
Probabilmente non è necessario conservare tutti i backup dall'era mesozoica, quindi potrebbe essere utile "ripulire" periodicamente il proprio storage (sia i "backup completi" sia i registri WAL). Lo faremo anche questo tramite 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 del mattino, eliminando tutto (backup completi, delta e WAL) tranne le copie degli ultimi 10 giorni, ma lascerà almeno un backup fino a della data specificata, affinché qualsiasi punto la data rientri nel PITR. la data rientri nel PITR.
Non è un segreto per nessuno che la chiave di una base dati sana è nel ripristino periodico e nella verifica dell'integrità dei dati all'interno. Come ripristinarsi utilizzando WAL-G – ve lo spiegherò in questa sezione, mentre parleremo dei controlli dopo.
Non è un segreto per nessuno che la chiave per una base sana è il ripristino periodico e la verifica dell'integrità dei dati all'interno. Come ripristinarsi utilizzando WAL-G – lo spiegherò in questo capitolo, mentre parleremo delle verifiche più avanti.
È importante notare che per il ripristino in un ambiente di test (tutto ciò che non è in produzione) è necessario utilizzare un account di sola lettura in S3, per non sovrascrivere accidentalmente i backup. Nel caso di WAL-G, è necessario assegnare all'utente S3 i seguenti diritti nella Group Policy (Effetto: Consenti): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. E, naturalmente, non dimenticate di impostare archive_mode=off nel file di configurazione , affinché il tuo database di test non voglia effettuare un backup silenziosamente., affinché il vostro database di test non desideri effettuare un backup silenzioso.
Il ripristino avviene con un semplice gesto di mano eliminando tutti i dati PostgreSQL (inclusi gli utenti), pertanto vi prego di prestare la massima attenzione quando eseguite 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 desiderano controllare il processo di ripristino, ecco un breve pezzo di magia bash, in modo che, in caso di problemi durante il ripristino, lo script termini con un codice di uscita diverso da zero. In questo esempio, vengono effettuati 120 controlli con un timeout di 5 secondi (in totale 10 minuti per il ripristino) per scoprire se il file segnale è stato rimosso (il che significherebbe che il ripristino è avvenuto con successo):
#!/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 un ripristino riuscito, non dimenticate di riavviare tutti i processi (pgbouncer/monit, ecc.).
Controllo dei dati dopo il ripristino
È fondamentale verificare l'integrità del database dopo il ripristino, per evitare che si verifichino situazioni con backup corrotti. È preferibile farlo con ogni archivio creato, ma dove e come — dipende solo dalla vostra creatività (se si possono avviare server separati con pagamento orario o eseguire controlli in CI). Ma almeno — è necessario controllare i dati e gli indici nel database.
Per controllare i dati è sufficiente passarli attraverso un dump, ma è meglio che, durante la creazione del database, siano attivate le somme di controllo ():
#!/bin/bash
if ! su - postgres -c 'pg_dumpall > /dev/null'
then
echo 'pg_dumpall failed'
exit 125
fi
Per controllare gli indici – esiste , la query SQL per esso la prenderemo da e costruiremo attorno a una piccola logica:
#!/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
In sintesi
Esprimo gratitudine ad Andrey Borodin per l'aiuto nella preparazione della pubblicazione e un ringraziamento speciale per il suo contributo allo sviluppo di WAL-G!
Con questo, questa nota giunge al termine. Spero di essere riuscito a trasmettere la facilità di configurazione e il grande potenziale di applicazione di questo strumento nella vostra azienda. Ho sentito molto parlare di WAL-G, ma non ho mai trovato il tempo per sedermi e capire. Dopo averlo implementato da me stesso, è nata questa articolo.
Vale la pena notare che WAL-G può anche lavorare con i seguenti DBMS:
- ;
- ;
- ;
- E a giudicare dai commit – se ne prevedono ancora altri!
Fonte: habr.com
