WAL-G: sigurnosna kopija i oporavak PostgreSQL DBMS-a

Odavno je poznato da pravljenje sigurnosne kopije u SQL dumpove (koristeći pg_dump ili pg_dumpall) nije dobra ideja. Da biste napravili rezervnu kopiju PostgreSQL DBMS-a, bolje je koristiti naredbu pg_basebackup, koji čini binarnu kopiju WAL dnevnika. Ali kada počnete proučavati cijeli proces kreiranja kopije i restauracije, shvatit ćete da morate napisati barem nekoliko tricikla da bi ovo funkcioniralo i da vam ne bi uzrokovalo bol i iznad i ispod. Za ublažavanje patnje razvijen je WAL-G.

WAL-G je alat napisan u Go za sigurnosno kopiranje i vraćanje PostgreSQL baza podataka (i nedavno MySQL/MariaDB, MongoDB i FoundationDB). Podržava rad sa Amazon S3 skladištem (i analognim, na primjer, Yandex Object Storage), kao i Google Cloud Storage, Azure Storage, Swift Object Storage i jednostavno sa sistemom datoteka. Cijelo podešavanje se svodi 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 (postoji nekoliko postova na Habréu, ali tu su propušteni mnogi poeni).

WAL-G: sigurnosna kopija i oporavak PostgreSQL DBMS-a

Ovaj članak je napisan prvenstveno da sistematizujem svoje znanje. Nisam DBA i mogu se negdje izraziti laičkim jezikom, tako da su svaka ispravka dobrodošla!

Odvojeno, napominjem da je sve ispod relevantno i testirano za PostgreSQL 12.3 na Ubuntu 18.04, sve komande moraju biti izvršene kao privilegovani korisnik.

postavljanje

U vrijeme pisanja ovog članka, stabilna verzija WAL-G je v0.2.15 (mart 2020.). Ovo je ono što ćemo koristiti (ali ako želite sami da ga napravite iz master grane, onda github spremište ima sve upute za ovo). Za preuzimanje i instaliranje potrebno je da uradite:

#!/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 toga, prvo morate konfigurirati WAL-G, a zatim i sam PostgreSQL.

Postavljanje WAL-G

Za primjer pohranjivanja sigurnosnih kopija koristit će se Amazon S3 (jer je bliži mojim serverima i njegova upotreba je vrlo jeftina). Za rad s njim potrebna vam je “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 fajl u početnom direktoriju postgres korisnika. Da biste ga kreirali, 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

Dozvolite mi da malo objasnim sve parametre:

  • WALG_S3_PREFIX – put do vašeg S3 bucketa u koji će biti učitane rezervne kopije (možete ili u root ili u folder);
  • AWS_ACCESS_KEY_ID – pristupni ključ u S3 (u slučaju oporavka na test serveru, ovi ključevi moraju imati Politiku samo za čitanje! Ovo je detaljnije opisano u odjeljku o oporavku.);
  • AWS_SECRET_ACCESS_KEY – tajni ključ u S3 memoriji;
  • WALG_COMPRESSION_METHOD – metoda kompresije, bolje je koristiti Brotli (pošto je ovo zlatna sredina između konačne veličine i brzine kompresije/dekompresije);
  • WALG_DELTA_MAX_STEPS – broj „delta“ prije kreiranja 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 podataka (možete saznati pokretanjem naredbe pg_lsclusters);
  • PGHOST – povezivanje s bazom podataka, s lokalnom sigurnosnom kopijom 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.

Postavljanje PostgreSQL-a

Da bi arhiver unutar baze podataka uploadovao WAL zapisnike u oblak i vratio ih iz njih (ako je potrebno), potrebno je postaviti nekoliko parametara u konfiguracijskoj datoteci /etc/postgresql/12/main/postgresql.conf. Samo za početak morate biti sigurnida nijedna od postavki ispod nije postavljena na bilo koju drugu vrijednost, tako da kada se konfiguracija ponovo učita, DBMS se ne sruši. Ove parametre možete dodati koristeći:

#!/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 koji se postavljaju:

  • wal_level – koliko informacija upisati u WAL logove, “replika” – upisati sve;
  • archive_mode – omogućiti preuzimanje WAL dnevnika pomoću naredbe iz parametra archive_command;
  • archive_command – komanda za arhiviranje završenog WAL dnevnika;
  • archive_timeout – arhiviranje dnevnika se vrši tek kada je završeno, ali ako vaš server promijeni/doda malo podataka u bazu podataka, onda ima smisla postaviti ograničenje ovdje u sekundama, nakon čega će se prisilno pozvati komanda arhiviranja (Svake sekunde intenzivno pišem u bazu podataka, pa sam odlučio da ovaj parametar ne postavljam u produkciji);
  • restore_command – naredba za vraćanje WAL dnevnika iz sigurnosne kopije će se koristiti ako „puna sigurnosna kopija“ (bazna sigurnosna kopija) nema 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 rezervnog rasporeda

Šta god da se kaže, najpogodniji način za pokretanje je cron. Ovo je ono što ćemo konfigurirati za kreiranje sigurnosnih kopija. Počnimo s naredbom za kreiranje pune sigurnosne kopije: u wal-g-u ovo je argument pokretanja 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 ukazuju na putanju do direktorija podataka - podsjećam vas da to možete saznati pokretanjem pg_lsclusters.

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

#!/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 svakog dana u 4:15 ujutro.

Brisanje starih rezervnih kopija

Najvjerovatnije, ne morate čuvati apsolutno sve sigurnosne kopije iz mezozojske ere, tako da će biti korisno povremeno "čistiti" svoju pohranu (i "pune sigurnosne kopije" i WAL dnevnike). Sve ćemo to uraditi 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 posljednjih 10 dana, ali ostavljajući barem jednu sigurnosnu kopiju do naveden datum tako da bilo koja tačka после datumi su uključeni u PITR.

Vraćanje iz sigurnosne kopije

Nije tajna da je ključ zdrave baze podataka periodično obnavljanje i provjera integriteta podataka koji se nalaze unutar njih. Reći ću vam kako se oporaviti koristeći WAL-G u ovom odjeljku, a o provjerama ćemo govoriti kasnije.

Treba napomenuti odvojeno da za vraćanje u probno okruženje (sve što nije produkcija) morate koristiti račun samo za čitanje u S3 kako ne biste slučajno prepisali sigurnosne kopije. U slučaju WAL-G, morate postaviti sljedeća prava za S3 korisnika u grupnim pravilima (Efekat: Dozvoli): s3: GetObject, s3:ListBucket, s3: GetBucketLocation. I, naravno, ne zaboravite podesiti archive_mode=isključeno u datoteci postavki postgresql.conf, tako da vaša testna baza podataka ne želi da bude tiha sigurnosna kopija.

Restauracija se izvodi laganim pokretom ruke brisanje svih PostgreSQL podataka (uključujući korisnike), stoga budite izuzetno oprezni kada izvodite 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 komad bash magije, tako da će se u slučaju problema u oporavku skripta srušiti sa 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 utvrdilo da li je 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 ponovo pokrenuti sve procese (pgbouncer/monit, itd.).

Provjera podataka nakon oporavka

Obavezno je provjeriti integritet baze podataka nakon restauracije, kako ne bi došlo do situacije s pokvarenom/krivom sigurnosnom kopijom. I bolje je to raditi sa svakom kreiranom arhivom, ali gdje i kako ovisi samo o vašoj mašti (možete podizati pojedinačne servere na sat vremena ili izvršiti provjeru u CI). Ali kao minimum, potrebno je provjeriti podatke i indekse u bazi podataka.

Da biste provjerili podatke, dovoljno ih je pokrenuti kroz dump, ali je bolje da prilikom kreiranja baze imate omogućene kontrolne sume (kontrolne sume 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 njega 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

Da rezimiramo

Želeo bih da izrazim svoju zahvalnost Andreju Borodinu na njegovoj pomoći u pripremi publikacije i posebnu zahvalnost za njegov doprinos razvoju WAL-G!

Ovim je zaključena ova bilješka. Nadam se da sam uspeo da prenesem lakoću podešavanja i ogroman potencijal za korišćenje ovog alata u vašoj kompaniji. Čuo sam mnogo o WAL-G-u, ali nikad nisam imao dovoljno vremena da sjednem i shvatim. I nakon što sam ga implementirao kod kuće, ovaj članak je izašao iz mene.

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

izvor: www.habr.com

Dodajte komentar