Už dávno sa vie, že robiť zálohy do SQL-dumpov (používajúc pg_dump alebo pg_dumpall) – nie je najlepší nápad. Pre zálohovanie databázy PostgreSQL je lepšie použiť príkaz pg_basebackup, ktorý vytvára binárnu kópiu WAL žurnálov. Ale keď začnete študovať celý proces vytvárania kópie a obnovovania, pochopíte, že potrebujete napísať aspoň pár trojkolesových bicyklov, aby to všetko fungovalo a nespôsobovalo vám bolesť ako nahoře, tak aj dole. Aby sa zmiernilo utrpenie, bol vyvinutý WAL-G.
– je nástroj napísaný v Go na zálohovanie a obnovovanie databáz PostgreSQL (a od nedávna aj MySQL/MariaDB, MongoDB a FoundationDB). Podporuje prácu s úložiskami Amazon S3 (a analogami, ako napríklad Yandex Object Storage), ako aj Google Cloud Storage, Azure Storage, Swift Object Storage a jednoducho so súborovým systémom. Celé nastavenie spočíva na jednoduchých krokoch, ale kvôli tomu, že články o ňom sú roztrúsené po internete – neexistuje úplný how-to manuál, ktorý by obsahoval všetky kroky od začiatku do konca (na Habré je niekoľko príspevkov, ale mnohé aspekty tam chýbajú).

Tento článok bol napísaný predovšetkým na to, aby som systematizoval svoje vedomosti. Nie som DBA a niekde sa môžem vyjadrovať bežným vývojárskym jazykom, preto sú vítané akékoľvek opravy!
Samostatne zdôrazním, že všetko nižšie uvedené je relevantné a overené pre PostgreSQL 12.3 na Ubuntu 18.04, všetky príkazy by mali byť vykonávané od privilegovaného používateľa.
Inštalácia
V čase písania tohto článku stabilná verzia WAL-G – . Tú budeme používať (ale ak sa rozhodnete zostaviť ho sami z master vetvy, v úložisku na github sú všetky inštrukcie na to). Pre stiahnutie a inštaláciu je potrebné vykonať:
#!/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/
Potom je potrebné najprv nakonfigurovať WAL-G, a potom samotný PostgreSQL.
Nastavenie WAL-G
Ako príklad úložiska záloh sa použije Amazon S3 (pretože je bližšie k mojim serverom a jeho použitie je veľmi lacné). Na jeho prácu je potrebný „s3-bucket“ a prístupové kľúče.
Vo všetkých predchádzajúcich článkoch o WAL-G sa používalo konfigurácie pomocou environmentálnych premenných, ale od tohto vydania je možné nastavenia umiestniť do v domovskej priečinke používateľa postgres. Na jeho vytvorenie vykonáme nasledujúci 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
Trochu vysvetlím všetky parametre:
- WALG_S3_PREFIX – cesta k vašemu S3-buketu, kam budú nahrávané zálohy (môže byť ako do koreňa, tak aj do priečinka);
- AWS_ACCESS_KEY_ID – prístupový kľúč do S3 (pri obnove na testovacom serveri – tieto kľúče by mali mať ReadOnly Policy! O tom je podrobnejšie písané v časti o obnove);
- AWS_SECRET_ACCESS_KEY – tajný kľúč v úložisku S3;
- WALG_COMPRESSION_METHOD – metóda kompresie, najlepšie použiť Brotli (pretože to je zlatý stred medzi konečnou veľkosťou a rýchlosťou kompresie/dekompresie);
- WALG_DELTA_MAX_STEPS – počet „delta“ pred vytvorením úplnej zálohy (umožňuje šetriť čas a veľkosť nahrávaných dát, ale môže mierne spomaliť proces obnovy, preto nie je žiaduce používať veľké hodnoty);
- PGDATA – cesta k priečinku s údajmi vašej databázy (môžete zistiť vykonaním príkazu pg_lsclusters);
- PGHOST – pripojenie k databáze, pri lokálnej zálohe je lepšie to robiť cez unix-socket ako v tomto príklade.
Ostatné parametre si môžete pozrieť v dokumentácii: .
Nastavenie PostgreSQL
Aby archivátor vo vnútri databázy sám nahrával WAL-žurnály do cloudu a obnovoval sa z nich (v prípade potreby) – treba nastaviť niekoľko parametrov v konfiguračnom súbore /etc/postgresql/12/main/postgresql.conf. Lenže na začiatok musíte sa uistiť, že žiadne z nižšie uvedených nastavení nemajú priradené iné hodnoty, aby pri reštartovaní konfigurácie – SDB netrpela. Tieto parametre môžete pridať pomocou:
#!/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
Popis nastavovaných parametrov:
- wal_level – koľko informácií písať do WAL žurnálov, „replica“ – písať všetko;
- archive_mode – zapnutie nahrávania WAL-žurnálov pomocou príkazu z parametra archive_command;
- archive_command – príkaz na archiváciu dokončeného WAL-žurnálu;
- archive_timeout – archivácia žurnálov prebieha iba v prípade, že je dokončený, ale ak váš server má málo zmien/pridaní údajov do DB, má zmysel nastaviť tu limit v sekundách, po uplynutí ktorého sa príkaz na archiváciu vyvolá nútene (u mňa intenzívny zápis do databázy každú sekundu, preto som sa vzdal nastavenia tohto parametra v produkcii);
- restore_command – príkaz na obnovenie WAL-žurnálu zo zálohy sa použije v prípade, že v „úplnej zálohe“ (base backup) budú chýbať posledné zmeny v DB.
Podrobnejšie o všetkých týchto parametroch si môžete prečítať v preklade oficiálnej dokumentácie: .
Nastavenie rozvrhu zálohovania
Ako sa hovorí, najužitočnejší spôsob spúšťania je cron. Práve ten si nastavíme na vytváranie záloh. Začnime príkazom na vytvorenie úplného zálohovania: v wal-g je to spúšťací argument. backup-push. Ale najprv je lepšie spustiť tento príkaz ručne ako používateľ postgres, aby sme sa uistili, že všetko funguje správne (a že nie sú žiadne prístupové chyby):
#!/bin/bash
su - postgres -c '/usr/local/bin/wal-g backup-push /var/lib/postgresql/12/main'
V spúšťacích argumentoch je uvedená cesta k adresáru s údajmi – pripomínam, že ju môžete zistiť vykonaním pg_lsclusters.
Ak prebehlo všetko bez chýb a údaje sa nahrali do úložiska S3, môžete ďalej nastaviť pravidelné spúšťanie 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 tomto príklade sa proces zálohovania spúšťa každý deň o 4:15 ráno.
Odstraňovanie starých záloh
Pravdepodobne nepotrebujete uchovávať všetky zálohy z druhohôr, preto bude užitočné pravidelne 'upratať' svoje úložisko (ako 'úplné zálohy', tak aj WAL záznamy). Urobíme to opäť cez cron úlohu:
#!/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 túto úlohu vykoná každý deň o 6:30 ráno, pričom odstráni všetko (úplné zálohy, delta a WAL) okrem kópií za posledných 10 dní, pričom aspoň jedna záloha z uvedeného dátumu zostane. do tak, aby akýkoľvek čas po bol zahrnutý do PITR.
Obnovenie zo zálohy
Nie je tajomstvom, že kľúčom k zdravej databáze je pravidelné obnovenie a kontrola integrity údajov. Ako sa obnoviť pomocou WAL-G – to vysvetlím v tejto časti, a o kontrolách budeme diskutovať neskôr.
Osobitne stojí za zmienku že na obnovenie v testovacom prostredí (všetko, čo nie je produkcia) – treba použiť Read Only účet v S3, aby sa náhodou neprepísali zálohy. V prípade WAL-G je potrebné zadať používateľovi S3 nasledujúce práva v Group Policy (Effect: Allow): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. A samozrejme, nezabudnúť nastaviť archive_mode=off v konfiguračnom súbore postgresql.conf, aby sa vaša testovacia databáza nechcela ticho zálohovať.
Obnovenie sa vykonáva jednoduchým pohybom ruky s odstránením všetkých údajov PostgreSQL (vrátane používateľov), preto buďte prosím mimoriadne opatrní, keď budete spúšťať nasledujúce príkazy.
#!/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
Pre tých, ktorí chcú sledovať proces obnovy — nižšie je pripravený malý kúsok bash-magie, aby sa v prípade problémov pri obnove skript zastavil s nenulovým exit kódom. V tomto príklade sa vykonáva 120 kontrol s časovým limitom 5 sekúnd (celkovo 10 minút na obnovu), aby sa zistil, či sa oznamovací súbor odstránil (to by znamenalo, že obnova prebehla úspešne):
#!/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 úspešnej obnove nezabudnite znovu spustiť všetky procesy (pgbouncer/monit a pod.).
Kontrola údajov po obnove
Je nevyhnutné skontrolovať integritu databázy po obnove, aby sa predišlo situácii s poškodenou/zlomenou zálohou. A je lepšie to robiť s každým vytvoreným archívom, ale kde a ako — to závisí len od vašej fantázie (môžete spúšťať samostatné servery na hodinovú platbu alebo vykonávať kontrolu v CI). Ale aspoň je potrebné kontrolovať údaje a indexy v databáze.
Na kontrolu údajov stačí prehnať ich cez dump, ale je lepšie, ak ste pri vytvorení databázy mali zapnuté kontrolné sumy ():
#!/bin/bash
if ! su - postgres -c 'pg_dumpall > /dev/null'
then
echo 'pg_dumpall failed'
exit 125
fi
Na kontrolu indexov existuje , sql-dotaz naň vezmeme z a okolo to vybudujeme malú logiku:
#!/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
Zhrňujúc
Vyjadrujem vďačnosť Andrejovi Borodinovi za pomoc pri príprave publikácie a špeciálne poďakovanie za jeho príspevok k rozvoju WAL-G!
Týmto sa táto poznámka končí. Dúfam, že som dokázal preniesť jednoduchosť nastavenia a obrovský potenciál pre využitie tohto nástroja vo vašej spoločnosti. Počul som veľa o WAL-G, ale nikdy nebolo času sadnúť si a pochopiť to. A po tom, ako som ho zaviedol u seba — vznikol z toho tento článok.
Zvlášť stojí za zmienku, že WAL-G môže pracovať aj s nasledujúcimi DBMS:
- ;
- ;
- ;
- A súdiac podľa commitov — očakáva sa ešte niekoľko!
Zdroj: habr.com
