È risaputo da tempo che fare backup in SQL dump (usando pg_dump o pg_dumpall) non è la scelta migliore. Per il backup del DBMS PostgreSQL è meglio utilizzare il comando pg_basebackup, che crea una copia binaria dei log WAL. Ma quando inizierai a studiare l'intero processo di creazione e ripristino del backup, capirai che è necessario scrivere almeno un paio di biciclette a tre ruote affinché tutto funzioni e non ti causi dolore sia sopra che sotto. Per alleviare queste 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 i repository Amazon S3 (e le alternative, come Yandex Object Storage), nonché Google Cloud Storage, Azure Storage, Swift Object Storage e semplicemente il filesystem. Tutta la configurazione si riduce a semplici passaggi, ma poiché gli articoli su di esso sono sparsi per internet, non esiste un manuale completo che includa tutti i passaggi dall'inizio alla fine (su Habr ci sono alcuni post, ma molti aspetti sono trascurati).

Questo articolo è scritto principalmente per sistematizzare le proprie conoscenze. Non sono un DBA e potrei esprimermi talvolta in termini più da sviluppatore, quindi qualsiasi correzione è benvenuta!
Voglio sottolineare che tutto ciò che segue è valido e testato 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 è quella che utilizzeremo (ma se desiderate compilarlo da soli dalla branch master, nel repository su GitHub ci sono tutte le istruzioni per farlo). Per scaricare e installare, è 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 ciò, è necessario configurare prima WAL-G e poi PostgreSQL.
Configurazione di WAL-G
Per la conservazione dei backup, utilizzeremo Amazon S3 (perché è più vicino ai miei server e il suo utilizzo è molto economico). Per lavorarci è necessario un "bucket S3" e le chiavi di accesso.
In tutti i precedenti articoli su WAL-G, la configurazione veniva effettuata tramite variabili d'ambiente, ma da questa versione è possibile posizionare le impostazioni nel nella directory home 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
Un po' di chiarimenti su tutti i parametri:
- WALG_S3_PREFIX – il percorso del tuo bucket S3 dove verranno caricati i backup (può essere sia alla radice che in una cartella);
- AWS_ACCESS_KEY_ID – chiave di accesso S3 (in caso di ripristino su un server di test – queste chiavi devono avere una politica ReadOnly! Maggiori dettagli sono scritti nella sezione sul ripristino.);
- AWS_SECRET_ACCESS_KEY – chiave segreta nel sistema S3;
- WALG_COMPRESSION_METHOD – metodo di compressione, è meglio usare Brotli (in quanto rappresenta un giusto compromesso tra dimensione finale e velocità di compressione/decompressione);
- WALG_DELTA_MAX_STEPS – numero di «delta» prima della creazione di un backup completo (consente di risparmiare tempo e dimensione dei dati caricati, ma può rallentare leggermente il processo di ripristino, quindi è sconsigliato usare valori elevati);
- PGDATA – percorso della directory con i dati del tuo database (può essere scoperto eseguendo il comando pg_lsclusters);
- PGHOST – connessione al database, durante il backup locale è meglio farlo tramite unix-socket come in questo esempio.
Puoi consultare gli altri parametri nella documentazione: .
Configurazione di PostgreSQL
Perché l'archiviatore all'interno del database carichi automaticamente i WAL log nel cloud e si ripristini da essi (se necessario) – è necessario impostare alcuni parametri nel file di configurazione. /etc/postgresql/12/main/postgresql.conf. Prima di tutto devi assicurarti, che nessuna delle impostazioni elencate di seguito sia impostata su valori diversi, affinché al riavvio della configurazione – il DBMS non si blocchi. Questi parametri possono essere aggiunti con:
#!/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 WAL log, «replica» – scrivere tutto;
- archive_mode – attivazione del caricamento dei WAL log utilizzando il comando dal parametro archive_command;
- archive_command – comando per l'archiviazione del WAL log completato;
- archive_timeout – l'archiviazione dei log avviene solo quando è completato, ma se il tuo server modifica/aggiunge pochi dati nel DB, ha senso impostare un limite in secondi, al termine del quale il comando di archiviazione sarà forzatamente chiamato (ho un'intensa scrittura nel database ogni secondo, quindi ho deciso di non impostare questo parametro in produzione.);
- restore_command – il comando per il ripristino del WAL dal backup sarà utilizzato nel caso in cui nel "backup completo" (base backup) manchino le ultime modifiche nel database.
Puoi leggere di più su tutti questi parametri nella traduzione della documentazione ufficiale: .
Impostazione del programma di backup
In ogni caso, il modo più conveniente per avviare è tramite cron. Infatti, è ciò che configureremo per creare i backup. Iniziamo con il comando per creare un backup completo: in wal-g è l'argomento di avvio backup-push. 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'
Nella lista degli argomenti di avvio è indicato il percorso alla directory con i dati – ricordo che può essere verificato eseguendo pg_lsclusters.
Se tutto è andato senza errori e i dati sono stati caricati nello storage S3, è possibile impostare 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 dei vecchi backup
Probabilmente non hai bisogno di conservare tutti i backup sin dall'era mesozoica, quindi è utile «ripulire» periodicamente il tuo spazio di archiviazione (sia i «backup completi» che i log WAL). Faremo tutto questo anche 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
Il 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 dalla data indicata, affinché ogni punto dopo la data rientri nel PITR.
Ripristino da backup
Non è un segreto che la salute di un database dipenda dal ripristino e dalla verifica periodica dell'integrità dei dati. Come ripristinare utilizzando WAL-G – lo descriverò in questa sezione, mentre parleremo dei controlli in seguito.
Vale la pena notare che per il ripristino in un ambiente di test (tutto ciò che non è produzione) – è necessario utilizzare un account in sola lettura in S3, per non sovrascrivere accidentalmente i backup. Nel caso di WAL-G, è necessario impostare i seguenti diritti all'utente S3 nella Group Policy (Effetto: Consenti): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. E, naturalmente, non dimenticare di impostare archive_mode=off nel file di configurazione postgresql.conf, affinché il tuo database di prova non voglia eseguire un backup in silenzio.
Il ripristino viene effettuato con un semplice gesto da rimuovendo tutti i dati di PostgreSQL (compresi gli utenti), quindi ti preghiamo di prestare la massima 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 chi desidera controllare il processo di ripristino, di seguito è preparato un piccolo pezzo di magia bash, in modo che in caso di problemi nel ripristino – lo script termini con un codice di uscita non nullo. In questo esempio vengono effettuati 120 controlli con un timeout di 5 secondi (per un totale di 10 minuti di ripristino), per scoprire se il file segnale è stato rimosso (questo significherà 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 un ripristino riuscito, non dimenticare di riavviare tutti i processi (pgbouncer/monit, ecc.).
Controllo dei dati dopo il ripristino
È fondamentale controllare l'integrità del database dopo il ripristino, per evitare situazioni di backup danneggiato o errato. E sarebbe meglio farlo con ogni archivio creato, ma dove e come – dipende solo dalla vostra fantasia (potete avviare singoli server a pagamento a ore oppure avviare il controllo in CI). Ma almeno – è necessario controllare i dati e gli indici nel database.
Per controllare i dati, è sufficiente eseguire un dump, ma è meglio avere attivate le somme di controllo durante la creazione del database ():
#!/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 questo la prenderemo da e attorno costruiremo una logica semplice:
#!/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 la mia gratitudine ad Andrey Borodin per l'aiuto nella preparazione della pubblicazione e un ringraziamento particolare per il suo contributo allo sviluppo di WAL-G!
Con questa nota, concludo. Spero di aver trasmesso la facilità di configurazione e l'enorme potenziale di utilizzo di questo strumento nella vostra azienda. Ho sentito molto parlare di WAL-G, ma non trovavo mai il tempo di sedermi e capirlo. Dopo averlo implementato, è nata questa articolo.
È importante notare che WAL-G può anche funzionare con i seguenti DBMS:
- ;
- ;
- ;
- E secondo gli aggiornamenti, sono previsti ulteriori sviluppi!
Fonte: habr.com
