WAL-G: sigurnosne kopije i oporavak PostgreSQL DBMS-a

Odavno je poznato da izrada sigurnosnih kopija u SQL dumpove (pomoću pg_dump ili pg_dumpall) nije dobra ideja. Za sigurnosno kopiranje PostgreSQL DBMS-a, bolje je koristiti naredbu pg_basebackup, koji čini binarnu kopiju WAL dnevnika. Ali kada počnete proučavati cijeli proces stvaranja kopije i restauracije, shvatit ćete da morate napisati barem par tricikla kako bi sve to funkcioniralo i ne bi vam zadavalo bol i odozgo i odozdo. Kako bi se ublažila patnja, razvijen je WAL-G.

WAL-G je alat napisan u Go za sigurnosno kopiranje i vraćanje PostgreSQL baza podataka (a odnedavno MySQL/MariaDB, MongoDB i FoundationDB). Podržava rad s pohranom Amazon S3 (i analozima, na primjer, Yandex Object Storage), kao i Google Cloud Storage, Azure Storage, Swift Object Storage i jednostavno sa sustavom datoteka. Cijelo postavljanje svodi se na jednostavne korake, ali zbog činjenice da su članci o tome razbacani po Internetu, ne postoji potpuni priručnik koji bi uključivao sve korake od početka do kraja (ima nekoliko postova na Habréu, ali tu su mnoge točke propuštene).

WAL-G: sigurnosne kopije i oporavak PostgreSQL DBMS-a

Ovaj članak je prvenstveno napisan kako bih sistematizirao svoje znanje. Nisam DBA i mogu se negdje izraziti laičkim jezikom, tako da su sve ispravke dobrodošle!

Zasebno napominjem da je sve u nastavku relevantno i testirano za PostgreSQL 12.3 na Ubuntu 18.04, sve se naredbe moraju izvršiti kao povlašteni korisnik.

Instalacija

U vrijeme pisanja ovog članka, stabilna verzija WAL-G-a je v0.2.15 (ožujak 2020.). Ovo ćemo koristiti (ali ako ga želite sami izgraditi iz glavne grane, tada github repozitorij ima sve upute za to). Za preuzimanje i instalaciju morate učiniti:

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

Nakon ovoga prvo trebate konfigurirati WAL-G, a zatim i sam PostgreSQL.

Postavljanje WAL-G

Za primjer pohranjivanja sigurnosnih kopija koristit će se Amazon S3 (jer je bliže mojim poslužiteljima i njegova je upotreba vrlo jeftina). Za rad s njime potrebni su vam “s3 bucket” i pristupni ključevi.

Svi prethodni članci o WAL-G-u koristili su konfiguraciju pomoću varijabli okruženja, ali s ovim izdanjem postavke se mogu nalaziti u .walg.json datoteku u početnom direktoriju postgres korisnika. Da biste ga stvorili, pokrenite sljedeću bash skriptu:

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

Dopustite mi da malo objasnim sve parametre:

  • WALG_S3_PREFIX – put do vaše S3 kante gdje će se sigurnosne kopije učitavati (možete ili u korijen ili u mapu);
  • AWS_ACCESS_KEY_ID – pristupni ključ u S3 (u slučaju oporavka na testnom poslužitelju, ovi ključevi moraju imati Politiku samo za čitanje! To je detaljnije opisano u odjeljku o oporavku.);
  • AWS_SECRET_ACCESS_KEY – tajni ključ u S3 pohrani;
  • WALG_COMPRESSION_METHOD – metoda kompresije, bolje je koristiti Brotli (budući da je to zlatna sredina između konačne veličine i brzine kompresije/dekompresije);
  • WALG_DELTA_MAX_KORAKA – broj „delta“ prije izrade pune sigurnosne kopije (štede vrijeme i veličinu preuzetih podataka, ali mogu malo usporiti proces oporavka, pa nije preporučljivo koristiti velike vrijednosti);
  • PGDATA – put do direktorija s podacima vaše baze (možete saznati pokretanjem naredbe pg_lsclusters);
  • PGHOST – povezivanje s bazom podataka, s lokalnim backupom bolje je to učiniti preko unix-socketa kao u ovom primjeru.

Ostale parametre možete pronaći u dokumentaciji: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

Konfiguriranje PostgreSQL-a

Kako bi arhivar unutar baze podataka učitao WAL zapisnike u oblak i iz njih ih vratio (ako je potrebno), potrebno je postaviti nekoliko parametara u konfiguracijskoj datoteci /etc/postgresql/12/main/postgresql.conf. Samo za početak morate se uvjeritida niti jedna od postavki u nastavku nije postavljena na druge vrijednosti, tako da se DBMS ne sruši kada se konfiguracija ponovno učita. Ove parametre možete dodati pomoću:

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

Opis parametara koje treba postaviti:

  • razina_zida – koliko informacija upisati u WAL zapisnike, “replika” – upisati sve;
  • arhivski_način – omogućiti preuzimanje WAL zapisnika naredbom iz parametra naredba_arhiva;
  • naredba_arhiva – naredba za arhiviranje završenog WAL dnevnika;
  • arhiva_timeout – arhiviranje logova vrši se tek kada je dovršeno, ali ako vaš poslužitelj mijenja/dodaje malo podataka u bazu, onda ima smisla ovdje postaviti ograničenje u sekundama, nakon čega će se naredba za arhiviranje prisilno pozvati (Intenzivno pišem u bazu svake sekunde, pa sam odlučio ne postavljati ovaj parametar u produkciji);
  • vraćanje_naredbe – naredba za vraćanje WAL dnevnika iz sigurnosne kopije koristit će se ako u “punoj sigurnosnoj kopiji” (baznoj sigurnosnoj kopiji) nedostaju najnovije promjene u bazi podataka.

Više o svim ovim parametrima možete pročitati u prijevodu službene dokumentacije: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Postavljanje rasporeda sigurnosnog kopiranja

Što god netko rekao, najprikladniji način za pokretanje je cron. Ovo ćemo konfigurirati za izradu sigurnosnih kopija. Počnimo s naredbom za stvaranje pune sigurnosne kopije: u wal-g ovo je argument za pokretanje backup-push. Ali prvo, bolje je pokrenuti ovu naredbu ručno od postgres korisnika kako biste bili sigurni da je sve u redu (i da nema grešaka u pristupu):

#!/bin/bash

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

Argumenti pokretanja označavaju put do direktorija s podacima - podsjećam vas da to možete pronaći pokretanjem pg_lsclusters.

Ako je sve prošlo bez grešaka i podaci su učitani u S3 pohranu, tada možete konfigurirati periodično pokretanje u crontabu:

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

U ovom primjeru, proces izrade sigurnosne kopije počinje svaki dan u 4:15 ujutro.

Brisanje starih sigurnosnih kopija

Najvjerojatnije ne morate čuvati apsolutno sve sigurnosne kopije iz mezozoika, pa će biti korisno povremeno "očistiti" svoju pohranu (i "pune sigurnosne kopije" i WAL zapisnike). Sve ćemo to učiniti kroz cron zadatak:

#!/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 će pokrenuti ovaj zadatak svaki dan u 6:30 ujutro, brišući sve (potpune sigurnosne kopije, delte i WAL-ove) osim kopija za zadnjih 10 dana, ali ostavljajući barem jednu sigurnosnu kopiju na navedeni datum tako da bilo koja točka nakon datumi su uključeni u PITR.

Vraćanje iz sigurnosne kopije

Nije tajna da je ključ zdrave baze podataka periodično vraćanje i provjera integriteta podataka koji se nalaze u njoj. Reći ću vam kako se oporaviti pomoću WAL-G-a u ovom odjeljku, a kasnije ćemo razgovarati o provjerama.

Treba to posebno napomenuti da za vraćanje u testnom okruženju (sve što nije proizvodnja) trebate koristiti račun samo za čitanje u S3 kako ne biste slučajno prebrisali sigurnosne kopije. U slučaju WAL-G, trebate postaviti sljedeća prava za S3 korisnika u pravilima grupe (Učinak: Dopusti): s3: GetObject, s3:ListBucket, s3:GetBucketLocation. I, naravno, ne zaboravite postaviti archive_mode=isključeno u datoteci postavki postgresql.conf, tako da se vaša testna baza podataka ne želi tiho sigurnosno kopirati.

Restauracija se izvodi laganim pokretom ruke brisanje svih PostgreSQL podataka (uključujući korisnike), stoga budite krajnje oprezni kada pokrećete sljedeće naredbe.

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

Za one koji žele provjeriti proces oporavka, u nastavku je pripremljen mali dio bash magije, tako da će se u slučaju problema u oporavku skripta srušiti s izlaznim kodom koji nije nula. U ovom primjeru, napravljeno je 120 provjera s vremenskim ograničenjem od 5 sekundi (ukupno 10 minuta za oporavak) kako bi se saznalo je li signalna datoteka izbrisana (to će značiti da je oporavak bio uspješan):

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

Nakon uspješnog oporavka, ne zaboravite ponovno pokrenuti sve procese (pgbouncer/monit, itd.).

Provjera podataka nakon oporavka

Neophodno je provjeriti integritet baze podataka nakon obnove, kako ne bi došlo do situacije s pokvarenom/iskrivljenom sigurnosnom kopijom. I bolje je to učiniti sa svakom stvorenom arhivom, ali gdje i kako ovisi samo o vašoj mašti (možete podizati pojedinačne poslužitelje na satnoj osnovi ili pokrenuti provjeru u CI-ju). Ali minimalno je potrebno provjeriti podatke i indekse u bazi podataka.

Za provjeru podataka dovoljno ih je provući kroz dump, ali je bolje da prilikom kreiranja baze imate uključene kontrolne zbrojeve (kontrolni zbrojevi podataka):

#!/bin/bash

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

Za provjeru indeksa - postoji amcheck modul, uzmimo sql upit za to iz WAL-G testovi i izgradi malo logike oko toga:

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

sažimanje

Želio bih izraziti svoju zahvalnost Andreju Borodinu na pomoći u pripremi publikacije i posebnu zahvalu za njegov doprinos razvoju WAL-G-a!

Ovo zaključuje ovu bilješku. Nadam se da sam uspio dočarati jednostavnost postavljanja i ogroman potencijal za korištenje ovog alata u vašoj tvrtki. Čuo sam puno o WAL-G-u, ali nikad nisam imao dovoljno vremena sjesti i shvatiti. I nakon što sam to implementirao kod kuće, ovaj članak je izašao iz mene.

Zasebno, vrijedi napomenuti da WAL-G također može raditi sa sljedećim DBMS-om:

Izvor: www.habr.com

Dodajte komentar