WAL-G: sikkerhetskopiering og gjenoppretting av PostgreSQL DBMS

Det har lenge vært kjent at sikkerhetskopiering til SQL-dumper (ved hjelp av pg_dump eller pg_dumpall) er ikke en god idé. For å sikkerhetskopiere PostgreSQL DBMS, er det bedre å bruke kommandoen pg_basebackup, som lager en binær kopi av WAL-logger. Men når du begynner å studere hele prosessen med å lage en kopi og gjenopprette, vil du forstå at du må skrive minst et par trehjulssykler for at dette skal fungere og ikke forårsake smerte både over og under. For å lindre lidelse ble WAL-G utviklet.

WAL-G er et verktøy skrevet i Go for sikkerhetskopiering og gjenoppretting av PostgreSQL-databaser (og mer nylig MySQL/MariaDB, MongoDB og FoundationDB). Den støtter arbeid med Amazon S3-lagring (og analoger, for eksempel Yandex Object Storage), samt Google Cloud Storage, Azure Storage, Swift Object Storage og enkelt med filsystemet. Hele oppsettet kommer ned til enkle trinn, men på grunn av det faktum at artikler om det er spredt over Internett, er det ingen komplett bruksanvisning som vil inkludere alle trinnene fra start til slutt (det er flere innlegg på Habré, men mange punkter er savnet der).

WAL-G: sikkerhetskopiering og gjenoppretting av PostgreSQL DBMS

Denne artikkelen ble først og fremst skrevet for å systematisere min kunnskap. Jeg er ikke en DBA og jeg kan uttrykke meg på lekmannsspråk et sted, så eventuelle rettelser er velkomne!

Separat bemerker jeg at alt nedenfor er relevant og testet for PostgreSQL 12.3 på Ubuntu 18.04, alle kommandoer må utføres som en privilegert bruker.

Installasjon

På tidspunktet for skriving av denne artikkelen er den stabile versjonen av WAL-G v0.2.15 (mars 2020). Dette er hva vi skal bruke (men hvis du vil bygge det selv fra mastergrenen, så har github-depotet alle instruksjonene for dette). For å laste ned og installere må du gjøre:

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

Etter dette må du konfigurere WAL-G først, og deretter PostgreSQL selv.

Sette opp WAL-G

For et eksempel på lagring av sikkerhetskopier, vil Amazon S3 bli brukt (fordi det er nærmere serverne mine og bruken er veldig billig). For å jobbe med det trenger du en "s3 bøtte" og tilgangsnøkler.

Alle tidligere artikler om WAL-G brukte konfigurasjon med miljøvariabler, men med denne utgivelsen kan innstillingene lokaliseres i .walg.json-fil i hjemmekatalogen til postgres-brukeren. For å lage det, kjør følgende 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

La meg forklare litt om alle parameterne:

  • WALG_S3_PREFIX – banen til S3-bøtten din der sikkerhetskopier skal lastes opp (du kan enten til roten eller til en mappe);
  • AWS_ACCESS_KEY_ID – tilgangsnøkkel i S3 (i tilfelle gjenoppretting på en testserver, må disse nøklene ha ReadOnly Policy! Dette er beskrevet mer detaljert i avsnittet om gjenoppretting.);
  • AWS_SECRET_ACCESS_KEY – hemmelig nøkkel i S3-lagring;
  • WALG_COMPRESSION_METHOD – kompresjonsmetode, det er bedre å bruke Brotli (siden dette er den gyldne middelvei mellom den endelige størrelsen og kompresjons-/dekompresjonshastigheten);
  • WALG_DELTA_MAX_STEPS – antall "deltaer" før du oppretter en fullstendig sikkerhetskopi (de sparer tid og størrelsen på nedlastede data, men kan redusere gjenopprettingsprosessen litt, så det er ikke tilrådelig å bruke store verdier);
  • PGDATA – bane til katalogen med databasedataene dine (du kan finne ut av det ved å kjøre kommandoen pg_lsclusters);
  • PGHOST – koble til databasen, med en lokal sikkerhetskopi er det bedre å gjøre det via en unix-socket som i dette eksemplet.

Andre parametere finner du i dokumentasjonen: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

Sette opp PostgreSQL

For at arkiveren i databasen skal laste opp WAL-logger til skyen og gjenopprette dem fra dem (om nødvendig), må du angi flere parametere i konfigurasjonsfilen /etc/postgresql/12/main/postgresql.conf. Bare til å begynne med du må sørge forat ingen av innstillingene nedenfor er satt til andre verdier, slik at når konfigurasjonen lastes inn på nytt, krasjer ikke DBMS. Du kan legge til disse parameterne ved å bruke:

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

Beskrivelse av parameterne som skal stilles inn:

  • wal_level – hvor mye informasjon som skal skrives i WAL-logger, “replika” – skriv alt;
  • arkivmodus – aktiver nedlasting av WAL-logger ved å bruke kommandoen fra parameteren arkiv_kommando;
  • arkiv_kommando – kommando for å arkivere en fullført WAL-logg;
  • arkiv_tidsavbrudd – arkivering av logger utføres først når den er fullført, men hvis serveren din endrer/legger til lite data til databasen, er det fornuftig å sette en grense her i sekunder, hvoretter arkiveringskommandoen vil bli kalt med tvang (Jeg skriver intensivt til databasen hvert sekund, så jeg bestemte meg for å ikke sette denne parameteren i produksjon);
  • restore_command – kommandoen for å gjenopprette WAL-loggen fra en sikkerhetskopi vil bli brukt hvis "full backup" (base backup) mangler de siste endringene i databasen.

Du kan lese mer om alle disse parameterne i oversettelsen av den offisielle dokumentasjonen: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Sette opp en tidsplan for sikkerhetskopiering

Uansett hva man kan si, er den mest praktiske måten å kjøre den på cron. Dette er hva vi vil konfigurere for å lage sikkerhetskopier. La oss starte med kommandoen for å lage en fullstendig sikkerhetskopi: i wal-g er dette lanseringsargumentet backup-push. Men først er det bedre å kjøre denne kommandoen manuelt fra postgres-brukeren for å sikre at alt er bra (og det er ingen tilgangsfeil):

#!/bin/bash

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

Lanseringsargumentene indikerer banen til datakatalogen - jeg minner deg om at du kan finne det ut ved å kjøre pg_lsclusters.

Hvis alt gikk uten feil og dataene ble lastet inn i S3-lagring, kan du deretter konfigurere periodisk oppstart i 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

I dette eksemplet starter sikkerhetskopieringsprosessen hver dag kl. 4:15.

Sletter gamle sikkerhetskopier

Mest sannsynlig trenger du ikke å beholde absolutt alle sikkerhetskopiene fra mesozoikumtiden, så det vil være nyttig å periodisk "rydde opp" lagringen (både "fullstendige sikkerhetskopier" og WAL-logger). Vi vil gjøre dette gjennom en cron-oppgave:

#!/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 kjører denne oppgaven hver dag kl. 6, og sletter alt (fullstendige sikkerhetskopier, deltaer og WALer) bortsett fra kopier for de siste 30 dagene, men legger igjen minst én sikkerhetskopi til angitt dato slik at ethvert punkt etter datoer ble inkludert i PITR.

Gjenoppretter fra en sikkerhetskopi

Det er ingen hemmelighet at nøkkelen til en sunn database er periodisk restaurering og verifisering av integriteten til dataene inne. Jeg vil fortelle deg hvordan du gjenoppretter med WAL-G i denne delen, og vi snakker om sjekker senere.

Det bør bemerkes separat at for å gjenopprette i et testmiljø (alt som ikke er produksjon) må du bruke en skrivebeskyttet konto i S3 for ikke å overskrive sikkerhetskopier ved et uhell. Når det gjelder WAL-G, må du angi følgende rettigheter for S3-brukeren i gruppepolicy (Effekt: Tillat): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. Og, selvfølgelig, ikke glem å stille inn arkivmodus=av i innstillingsfilen postgresql.conf, slik at testdatabasen din ikke ønsker å sikkerhetskopieres stille.

Restaurering utføres med en liten bevegelse av hånden sletter alle PostgreSQL-data (inkludert brukere), så vær ekstremt forsiktig når du kjører følgende kommandoer.

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

For de som vil sjekke gjenopprettingsprosessen, er det utarbeidet et lite stykke bash-magi nedenfor, slik at i tilfelle problemer med gjenoppretting vil skriptet krasje med en utgangskode som ikke er null. I dette eksemplet utføres 120 kontroller med en tidsavbrudd på 5 sekunder (totalt 10 minutter for gjenoppretting) for å finne ut om signalfilen ble slettet (dette vil bety at gjenopprettingen var vellykket):

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

Etter vellykket gjenoppretting, ikke glem å starte alle prosesser tilbake (pgbouncer/monit, etc.).

Kontrollerer data etter gjenoppretting

Det er viktig å sjekke integriteten til databasen etter gjenoppretting, slik at det ikke oppstår en situasjon med ødelagt/skjev backup. Og det er bedre å gjøre dette med hvert opprettet arkiv, men hvor og hvordan avhenger bare av fantasien din (du kan heve individuelle servere på timebasis eller sjekke inn CI). Men som et minimum er det nødvendig å sjekke dataene og indeksene i databasen.

For å sjekke dataene er det nok å kjøre dem gjennom en dump, men det er bedre at når du oppretter databasen har du aktivert kontrollsummer (datasjekksummer):

#!/bin/bash

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

For å sjekke indekser - finnes amcheck-modul, la oss ta sql-søket for det fra WAL-G tester og bygg litt logikk rundt det:

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

Å oppsummere

Jeg vil gjerne uttrykke min takknemlighet til Andrey Borodin for hans hjelp med å forberede publikasjonen og spesiell takk for hans bidrag til utviklingen av WAL-G!

Dette avslutter dette notatet. Jeg håper at jeg klarte å formidle det enkle oppsettet og det enorme potensialet for å bruke dette verktøyet i din bedrift. Jeg hørte mye om WAL-G, men hadde aldri nok tid til å sette meg ned og finne ut av det. Og etter at jeg implementerte det hjemme, kom denne artikkelen ut av meg.

Separat er det verdt å merke seg at WAL-G også kan fungere med følgende DBMS:

Kilde: www.habr.com

Legg til en kommentar