Že dolgo je znano, da opravljanje varnostnih kopij v SQL datoteke (z uporabo pg_dump ili pg_dumpall) ni najboljša ideja. Za varnostno kopiranje PostgreSQL baz podatkov je bolje uporabiti ukaz pg_basebackup, ki ustvari binarno kopijo WAL dnevnikov. Ko pa začnete raziskovati celoten postopek ustvarjanja kopije in obnove, boste spoznali, da je treba napisati vsaj nekaj tricyklov, da vse deluje in ne povzroča bolečine zgoraj kot spodaj. Da bi olajšali trpljenje, je bil razvit WAL-G.
je orodje, napisano v Go za varnostno kopiranje in obnovo PostgreSQL baz podatkov (v zadnjem času pa tudi MySQL/MariaDB, MongoDB in FoundationDB). Podpira delo z Amazon S3 shrambami (in alternativami, na primer Yandex Object Storage), pa tudi Google Cloud Storage, Azure Storage, Swift Object Storage in preprosto s datotečnim sistemom. Vsa nastavitev je preprosta, vendar zaradi razdrobljenosti člankov o njem po internetu ni popolnega how-to priročnika, ki bi vseboval vse korake od začetka do konca (na Habrju je nekaj objav, vendar so mnogi trenutki tam spregledani).

Ta članek je pisan predvsem za sistematizacijo lastnega znanja. Nisem DBA in kje lahko uporabljam bolj vsakdanji-jezik razvijalcev, zato so dobrodošle vse popravke!
Poudariti moram, da so vsi spodaj navedeni podatki relevantni in preverjeni za PostgreSQL 12.3 na Ubuntu 18.04, vse ukaze morate izvajati iz privilegiranega uporabnika.
Namestitev
Ob trenutku pisanja tega članka je stabilna različica WAL-G – . To bomo uporabljali (ampak če se boste želeli sami sestaviti iz master-veje, so v repozitoriju na githubu vse navodila za to). Za prenos in namestitev je potrebno izvesti:
#!/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/
Nato morate najprej konfigurirati WAL-G, nato pa PostgreSQL.
Konfiguracija WAL-G
Za primer shranjevanja varnostnih kopij se bo uporabljal Amazon S3 (saj je bližje mojim strežnikom in njegova uporaba je zelo poceni). Za delo z njim potrebujete „s3-bucket“ in dostopne ključe.
V vseh prejšnjih člankih o WAL-G se je uporabljala konfiguracija z okolijskimi spremenljivkami, vendar od te različice naprej lahko nastavitve postavite v v domači mapi uporabnika postgres. Za njeno ustvarjanje izvedite naslednji bash skript:
#!/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
Malcolm razložiti o vseh parametrih:
- WALG_S3_PREFIX – pot do vašega S3-bucket-a, kamor se bodo nalagali varnostni kopiji (lahko tudi v koren ali v mapo);
- AWS_ACCESS_KEY_ID – ključ za dostop do S3 (v primeru obnove na testnem strežniku – ti ključi morajo imeti ReadOnly politiko! O tem je več opisano v razdelku o obnovitvi);
- AWS_SECRET_ACCESS_KEY – skrivni ključ v S3 skladišču;
- WALG_COMPRESSION_METHOD – metoda kompresije, najbolje je uporabiti Brotli (ker je to zlata sredina med končno velikostjo in hitrostjo stiskanja/razstavljanja);
- WALG_DELTA_MAX_STEPS – število "delta" do ustvarjanja popolne varnostne kopije (omogočajo prihranek časa in velikosti prenosljivih podatkov, lahko pa nekoliko upočasnijo postopek obnove, zato ni priporočljivo uporabljati velikih vrednosti);
- PGDATA – pot do direktorija s podatki vaše baze (lahko izveste z izvedbo ukaza pg_lsclusters);
- PGHOST – povezava do baze, pri lokalni varnostni kopiji je najbolje uporabiti unix-socket, kot v tem primeru.
Preostale parametre lahko pogledate v dokumentaciji: .
Nastavitev PostgreSQL
Da archiver znotraj baze sam nalaga WAL-dnevniške datoteke v oblak in se obnavlja iz njih (v primeru potrebe) – potrebno je določiti nekaj parametrov v konfiguracijski datoteki /etc/postgresql/12/main/postgresql.conf. Najprej se morate prepričati, da nobena od spodaj navedenih nastavitev ni nastavljena na druge vrednosti, da se ob ponovnem nalaganju konfiguracije – DBMS ne zruši. Te parametre lahko dodate pomoč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 nastavljajočih parametrov:
- wal_level – koliko informacij zapisati v WAL dnevnike, "replica" – zapisati vse;
- archive_mode – vklop nalaganja WAL-dnevnikov z uporabo ukaza iz parametra archive_command;
- archive_command – ukaz za arhiviranje končanega WAL-dnevnika;
- archive_timeout – arhiviranje dnevnikov se izvede le, ko je končan, a če vaš strežnik redko spreminja/doda podatke v bazo, ima smisel nastaviti tukaj omejitev v sekundah, po kateri bo ukaz arhiviranja klican prisilno (pri meni intenzivno zapisovanje v bazo vsako sekundo, zato sem se odločil, da tega parametra ne nastavljam v proizvodnji);
- restore_command – ukaz za obnovitev WAL-dnevnika iz varnostne kopije, bo uporabljen, če bo v "popolni varnostni kopiji" (base backup) manjkalo zadnjih sprememb v bazi.
Več o vseh teh parametrih lahko preberete v prevedeni uradni dokumentaciji: .
Nastavitev razporeda varnostnega kopiranja
Kako koli obračaš, je najudobnejši način za zagon – cron. Prav njega bomo nastavili za ustvarjanje varnostnih kopij. Začnimo z ukazom za ustvarjanje popolne varnostne kopije: v wal-g je to zagonski argument backup-push. Najprej pa je najbolje, da ta ukaz izvedete ročno kot uporabnik postgres, da se prepričate, da je vse v redu (in da ni kakšnih težav s dostopom):
#!/bin/bash
su - postgres -c '/usr/local/bin/wal-g backup-push /var/lib/postgresql/12/main'
V zagonskih argumentih je navedena pot do imenika s podatki – spomnite se, da jo lahko izveste, če izvedete pg_lsclusters.
Če je vse potekalo brez napak in so se podatki naložili v skladišče S3, lahko nato nastavite periodični zagon v 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
V tem primeru se postopek varnostnega kopiranja sproži vsak dan ob 4:15.
Brisanje starih varnostnih kopij
Verjetno vam ni treba hraniti prav vseh varnostnih kopij iz mezozojske dobe, zato bo koristno občasno 'počistiti' vaše skladišče (tako 'polne varnostne kopije' kot tudi WAL dnevnike). To bomo izvedli prav tako prek cron naloge:
#!/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 bo to nalogo izvajal vsak dan ob 6:30 zjutraj, pri čemer bo odstranil vse (polne varnostne kopije, delte in WAL-e) razen kopij za zadnjih 10 dni, a bo pustil vsaj eno varnostno kopijo do navedene datuma, da se katerikoli datum po datumu ujame v PITR.
Obnova iz varnostne kopije
Za nikogar ni skrivnost, da je ključ zdrave baze v periodični obnovi in preverjanju celovitosti podatkov. Kako obnoviti s pomočjo WAL-G – bom razložil v tem razdelku, o preverjanju pa bomo govorili kasneje.
Posebej je treba omeniti da za obnovo v testnem okolju (vse, kar ni produkcija) – morate uporabiti račun Read Only v S3, da ne bi nenamerno prepisali varnostnih kopij. V primeru WAL-G je treba uporabniku S3 dodeliti naslednja dovoljenja v Group Policy (Effect: Allow): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. In seveda ne pozabite nastaviti archive_mode=off v nastavitvenem datoteki postgresql.conf, da vaša testna baza ne bi želela tiho ustvariti varnostne kopije.
Obnova se izvede z enostavnim dejanjem z brisanjem vseh podatkov PostgreSQL (vključno z uporabniki), zato bodite, prosim, izjemno previdni, ko boste zagnali naslednje ukaze.
#!/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 tiste, ki želijo preveriti postopek obnovitve — spodaj je pripravljen majhen kos bash-magic, da v primeru težav pri obnovitvi – skript pade z nenulodno izhodno kodo. V tem primeru je izvedenih 120 preverjanj s časovno omejitvijo 5 sekund (skupaj 10 minut za obnovitev), da bi ugotovili, ali je bil signali datoteka izbrisana (kar bi pomenilo, da je obnovitev potekala uspešno):
#!/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
Po uspešni obnovitvi ne pozabite znova zagnati vseh procesov (pgbouncer/monit itd.).
Preverjanje podatkov po obnovitvi
Obvezno je preveriti celovitost baze po obnovitvi, da ne pride do situacije s pokvarjeno/kratko varnostno kopijo. Bolje je to narediti pri vsakem ustvarjenem arhivu, vendar kje in kako – je odvisno samo od vaše domišljije (lahko postavite ločene strežnike na urni osnovi ali zaženete preverjanje v CI). Vsaj pa je potrebno preveriti podatke in indekse v bazi.
Za preverjanje podatkov je dovolj, da jih poženete skozi izvoz, a bolje je, da so pri ustvarjanju baze vključeni kontrolni seštevek ():
#!/bin/bash
if ! su - postgres -c 'pg_dumpall > /dev/null'
then
echo 'pg_dumpall failed'
exit 125
fi
Za preverjanje indeksov – obstaja , SQL-poizvedbo pa bomo vzeli iz in okoli tega zgradili majhno logiko:
#!/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
Ob zaključku
Izražam hvaležnost Andreyju Borodinu za pomoč pri pripravi objave in posebej se mu zahvaljujem za njegov prispevek k razvoju WAL-G!
S tem je ta opomba zaključena. Upam, da sem uspelo prenesti enostavnost nastavitve in ogromen potencial za uporabo tega orodja v vašem podjetju. O WAL-G sem slišal veliko, vendar nikoli nisem imel časa, da bi se usedel in razumel. Po tem, ko sem ga uvedel pri sebi – iz mene je nastal ta članek.
Ločeno je vredno omeniti, da WAL-G lahko dela tudi z naslednjimi DBMS:
- ;
- ;
- ;
- In glede na commit-e – pričakuje se še več!
Izvor: habr.com
