WAL-G: dublēšana un PostgreSQL datu bāzes atjaunošana

Jau seniai ir zināms, ka veikt dublējumus SQL dump formātā (izmantojot pg_dump vai pg_dumpall) – nav labākā ideja. Lai dublētu PostgreSQL datu bāzi, labāk izmantot komandu pg_basebackup, kas izveido bināro kopiju WAL žurnāliem. Taču, kad sāksiet izpētīt visu procesu, kā izveidot kopiju un atjaunot to, sapratīsiet, ka nepieciešams uzrakstīt vismaz pāris trīsriteņu velosipēdus, lai viss darbotos un neradītu sāpes gan augšā, gan apakšā. Lai atvieglotu ciešanas, tika izstrādāts WAL-G.

WAL-G – ir rīks, kas rakstīts Go valodā, lai dublētu un atjaunotu PostgreSQL datu bāzes (un, pašu neseno laiku, arī MySQL/MariaDB, MongoDB un FoundationDB). Tas atbalsta darbu ar Amazon S3 (un analogiem, piemēram, Yandex Object Storage), kā arī Google Cloud Storage, Azure Storage, Swift Object Storage un vienkārši ar failu sistēmu. Visa konfigurācija sastāv no vienkāršiem soļiem, bet tāpēc, ka raksti par to ir izkaisīti pa internetu – nav pilnīga how-to rokasgrāmata, kas ietver visus soļus no un līdz (Habrā ir pāris ziņas, bet daudz aspektu tur nav iekļauti).

WAL-G: dublēšana un PostgreSQL datu bāzes atjaunošana

Šis raksts ir rakstīts pirmkārt, lai sakārtotu savas zināšanas. Es neesmu DBA un dažviet varu izteikties kā parasts izstrādātājs, tāpēc visus labojumus laipni gaidīšu!

Atsevišķi atzīmēju, ka viss zemāk minētais ir aktuāls un pārbaudīts PostgreSQL 12.3 uz Ubuntu 18.04, visām komandām jāizpildās ar privilēģētu lietotāju.

Uzstādīšana

Raksta rakstīšanas brīdī stabilā versija WAL-G – v0.2.15 (martā 2020). Tieši to mēs izmantosim (bet, ja vēlaties to apkopot no master zaru, tad repozitorijā uz github ir visas instrukcijas tam). Lai lejupielādētu un instalētu, jāveic sekojošais:

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

Pēc tam jāsakonfigurē vispirms WAL-G, un tad pats PostgreSQL.

WAL-G konfigurācija

Piemēram, dublējumu uzglabāšanai tiks izmantots Amazon S3 (jo tas ir tuvāk maniem serveriem un tā izmantošana ir ļoti lēta). Lai strādātu ar to, nepieciešams „s3-konteiners” un piekļuves atslēgas.

Visās iepriekšējās WAL-G rakstos tika izmantota konfigurācija, izmantojot vides mainīgos, taču kopš šī izlaiduma iestatījumus var izvietot .walg.json failā lietotāja postgres mājas direktorijā. Lai to izveidotu, izpildīsim sekojoš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

Nedaudz paskaidrošu par visiem parametriem:

  • WALG_S3_PREFIX – ceļš uz jūsu S3 tvertni, kur tiks augšupielādēti dublējumi (to var norādīt gan kā saknes ceļu, gan kā mapi);
  • AWS_ACCESS_KEY_ID – piekļuves atslēga S3 (ja atjaunošanas procesā testēšanas serverī – šīm atslēgām ir jābūt ReadOnly Policy! Par to ir sīkāk rakstīts atjaunošanas sadaļā.);
  • AWS_SECRET_ACCESS_KEY – slepenā atslēga S3 glabātavā;
  • WALG_COMPRESSION_METHOD – kompresijas metode, ieteicams izmantot Brotli (jo tā ir optimāla kombinācija starp gala izmēru un saspiešanas/izsaspiešanas ātrumu);
  • WALG_DELTA_MAX_STEPS – «delta» skaits pirms pilna dublējuma izveides (ļauj ietaupīt laiku un augšupielādējamo datu apjomu, taču var nedaudz palēnināt atjaunošanas procesu, tāpēc nevajadzētu izmantot lielus skaitļus);
  • PGDATA – ceļš uz direktoriju ar jūsu datu bāzes datiem (to var uzzināt, izpildot komandu pg_lsclusters);
  • PGHOST – pieslēgšanās pie datu bāzes, vietējā dublējumā labāk izmantot unix-socket, kā šajā piemērā.

Pārējās parametru iespējas var apskatīt dokumentācijā: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

PostgreSQL konfigurācija

Lai arhivētājs datu bāzē pats augšupielādētu WAL žurnālus mākoņos un nepieciešamības gadījumā tos atjaunotu – jānorāda vairāki parametri konfigurācijas failā /etc/postgresql/12/main/postgresql.conf. Pirms tam jums jāpārliecinās, ka neviena no zemāk norādītajām iestatījumu vērtībām nav noteikta kādās citās vērtībās, lai pārkonfigurācijas atkārtošanas gadījumā – DBMS neapstātos. Šos parametrus var pievienot ar:

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

Apraksts iestatītajiem parametriem:

  • wal_level – cik daudz informācijas rakstīt WAL žurnālos, «replica» – rakstīt visu;
  • archive_mode – WAL žurnālu augšupielādes aktivizēšana, izmantojot parametra komandu archive_command;
  • archive_command – komanda, lai arhivētu pabeigto WAL žurnālu;
  • archive_timeout – žurnālu arhivēšana tiek veikta tikai tad, kad tas ir pabeigts, taču, ja jūsu serveris veic maz izmaiņu/pievienojumu datiem DB, ir jēga noteikt laika ierobežojumu sekundēs, pēc kura arhivēšanas komanda tiks izsaukta piespiedu kārtā (man ir intensīva rakstīšana datu bāzē katru sekundi, tāpēc es atteicos no šī parametra uzstādīšanas ražošanā.);
  • restore_command – WAL žurnāla atjaunošanas komanda no dublējuma, tiks izmantota gadījumā, ja «pilnā dublējumā» (bāzes dublējums) trūks jaunāko izmaiņu datu bāzē.

Sīkāk par visiem šiem parametriem var izlasīt oficiālās dokumentācijas tulkojumā: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Rezervēšanas grafika konfigurācija

Neskatoties uz visu, visērtākais veids, kā uzsākt, ir cron. Tieši to mēs iestatīsim, lai izveidotu dublējumus. Sāksim ar komandu pilna dublējuma izveidei: wal-g tas ir palaišanas arguments. backup-push. Bet vispirms labāk šo komandu izpildīt manuāli no postgres lietotāja, lai pārliecinātos, ka viss ir labi (un nav piekļuves kļūdu):

#!/bin/bash

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

Palaišanas argumentos ir norādīta ceļa uz datu direktoriju – atgādinu, ka to var uzzināt, veicot pg_lsclusters.

Ja viss izdevās bez kļūdām un dati tika augšupielādēti S3 glabātavā, tad tālāk var iestatīt periodisku palaišanu 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

Šajā piemērā dublēšanas process tiek uzsākts katru dienu plkst. 4:15 no rīta.

Veco dublējumu dzēšana

Visticamāk, jums nav nepieciešams glabāt visus dublējumus no mezozoiskās ēras, tāpēc būs noderīgi periodiski "attīrīt" savu glabātuvi (gan "pilnos dublējumus", gan WAL žurnālus). To mēs darīsim caur cron uzdevumu:

#!/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 izpildīs šo uzdevumu katru dienu plkst. 6:30 no rīta, dzēšot visu (pilnos dublējumus, deltas un WALs), izņemot kopijas pēdējo 10 dienu laikā, bet saglabājot vismaz vienu dublējumu līdz norādītajā datumā, lai jebkurš punkts pārslēgšanās datē iekļautos PITR.

Atjaunošana no dublējuma

Nevienam nav noslēpums, ka veselīgas datu bāzes atslēga ir periodiska atjaunošana un datu integritātes pārbaude. Kā atjaunoties, izmantojot WAL-G – pastāstīšu šajā sadaļā, bet par pārbaudēm runāsim vēlāk.

Atsevišķi jāatzīmē ka atjaunošanai testēšanas vidē (visu to, kas nav ražošanā) – jāizmanto Read Only konts S3, lai netiktu nejauši pārrakstīti dublējumi. Attiecībā uz WAL-G nepieciešams noteikt S3 lietotājam šādas tiesības Grupas politikā (Ietekme: Atļaut): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. Un, protams, iepriekš neaizmirstiet norādīt archive_mode=off konfigurācijas failā postgresql.conf, lai jūsu testēšanas datu bāze negribētu pavisam klusi izveidot dublējumu.

Atjaunošanu veic ar vieglu rokas kustību, izdzēšot visus PostgreSQL datus (ieskaitot lietotājus), tāpēc, lūdzu, esiet ļoti uzmanīgi, kad izpildāt nākamās komandas.

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

Priekš tiem, kas vēlas pārbaudīt atjaunošanas procesu — zemāk ir sagatavota neliela bash burvība, lai, ja rodas problēmas atjaunošanā, skripts beigtos ar nenulles exit kodu. Šajā piemērā tiek veiktas 120 pārbaudes ar 5 sekunžu taimeri (kopā 10 minūtes atjaunošanai), lai noskaidrotu, vai signāla fails ir dzēsts (tas nozīmēs, ka atjaunošana bija veiksmīga):

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

Pēc veiksmīgas atjaunošanas neaizmirstiet atgriezt visus procesus (pgbouncer/monit utt.).

Datu pārbaude pēc atjaunošanas

Obligāti jāpārbauda datu integritāte pēc atjaunošanas, lai neveidotos situācija ar bojātu/krivu rezerves kopiju. Un labāk to darīt ar katru izveidoto arhīvu, bet kur un kā — tas atkarīgs tikai no jūsu iztēles (varat uzstādīt atsevišķus serverus uz stundas likmi vai palaist pārbaudi CI). Bet vismaz — nepieciešams pārbaudīt datus un indeksus datubāzē.

Lai pārbaudītu datus, pietiek tos palaist caur dublējumu, bet labāk, lai, izveidojot datubāzi, jūs būtu ieslēguši kontrolsummas (data checksums):

#!/bin/bash

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

Lai pārbaudītu indeksus — pastāv modulis amcheck, SQL vaicājumu ņemsim no WAL-G testiem un ap to izveidosim nelielu loģiku:

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

Kopsavilkumā

Izsaku pateicību Andrejam Borodinam par palīdzību publikācijas sagatavošanā un atsevišķs paldies par viņa ieguldījumu WAL-G izstrādē!

Uz šo brīdi šī piezīme ir beigusies. Ceru, ka izdevās nodot vieglumu, kādā varat iestatīt un milzīgu potenciālu šī rīka pielietošanai jūsu uzņēmumā. Es ļoti daudz dzirdēju par WAL-G, bet nekad nepietika laika sēdēt un izprast. Bet pēc tam, kad ieviesu to pie sevis, radās šī raksts.

Atsevišķi jāatzīmē, ka WAL-G var arī strādāt ar šādām DBMS:

Avots: habr.com

Iegādājieties uzticamu tīmekļa hostingu ar DDoS aizsardzību, VPS VDS serveriem 🔥 Iegādājieties uzticamu tīmekļa hostingu ar DDoS aizsardzību, VPS VDS serveriem | ProHoster