WAL-G: sikkerhedskopier og gendannelse af PostgreSQL DBMS

Det har længe været kendt, at sikkerhedskopiering til SQL-dumps (ved hjælp af pg_dump eller pg_dumpall) er ikke en god idé. For at tage backup af PostgreSQL DBMS er det bedre at bruge kommandoen pg_basebackup, som laver en binær kopi af WAL-logfiler. Men når du begynder at studere hele processen med at oprette en kopi og gendanne, vil du forstå, at du skal skrive mindst et par trehjulede cykler for at dette skal fungere og ikke forårsage smerte både over og under. For at lindre lidelse blev WAL-G udviklet.

WAL-G er et værktøj skrevet i Go til sikkerhedskopiering og gendannelse af PostgreSQL-databaser (og for nylig MySQL/MariaDB, MongoDB og FoundationDB). Det understøtter arbejde med Amazon S3-lagring (og analoger, for eksempel Yandex Object Storage), samt Google Cloud Storage, Azure Storage, Swift Object Storage og ganske enkelt med filsystemet. Hele opsætningen kommer ned til enkle trin, men på grund af det faktum, at artikler om det er spredt ud over internettet, er der ingen komplet vejledning, der vil omfatte alle trinene fra start til slut (der er flere indlæg på Habré, men der mangler mange punkter).

WAL-G: sikkerhedskopier og gendannelse af PostgreSQL DBMS

Denne artikel er primært skrevet for at systematisere min viden. Jeg er ikke DBA, og jeg kan udtrykke mig på lægmandssprog et eller andet sted, så enhver rettelse er velkommen!

Separat bemærker jeg, at alt nedenfor er relevant og testet for PostgreSQL 12.3 på Ubuntu 18.04, alle kommandoer skal udføres som en privilegeret bruger.

Installation

På tidspunktet for skrivning af denne artikel er den stabile version af WAL-G v0.2.15 (marts 2020). Dette er hvad vi vil bruge (men hvis du vil bygge det selv fra master-grenen, så har github-lageret alle instruktionerne til dette). For at downloade og installere skal du gø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/

Herefter skal du først konfigurere WAL-G og derefter selve PostgreSQL.

Opsætning af WAL-G

Som et eksempel på lagring af sikkerhedskopier vil Amazon S3 blive brugt (fordi det er tættere på mine servere, og det er meget billigt at bruge det). For at arbejde med det har du brug for en "s3 bucket" og adgangsnøgler.

Alle tidligere artikler om WAL-G brugte konfiguration ved hjælp af miljøvariabler, men med denne udgivelse kan indstillingerne findes i .walg.json-fil i postgres-brugerens hjemmemappe. For at oprette det skal du køre følgende bash-script:

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

Lad mig forklare lidt om alle parametrene:

  • WALG_S3_PREFIX – stien til din S3-bøtte, hvor sikkerhedskopier vil blive uploadet (du kan enten til roden eller til en mappe);
  • AWS_ACCESS_KEY_ID – adgangsnøgle i S3 (i tilfælde af gendannelse på en testserver, skal disse nøgler have ReadOnly Policy! Dette er beskrevet mere detaljeret i afsnittet om nyttiggørelse.);
  • AWS_SECRET_ACCESS_KEY – hemmelig nøgle i S3-lageret;
  • WALG_COMPRESSION_METHOD – kompressionsmetode, det er bedre at bruge Brotli (da dette er den gyldne middelvej mellem den endelige størrelse og kompressions-/dekompressionshastigheden);
  • WALG_DELTA_MAX_STEPS – antallet af "deltaer" før oprettelse af en fuld sikkerhedskopi (de sparer tid og størrelsen af ​​downloadede data, men kan bremse gendannelsesprocessen en smule, så det er ikke tilrådeligt at bruge store værdier);
  • PGDATA – sti til biblioteket med dine databasedata (du kan finde ud af det ved at køre kommandoen pg_lsclusters);
  • PGHOST – tilslutning til databasen, med en lokal backup er det bedre at gøre det via en unix-socket som i dette eksempel.

Andre parametre kan findes i dokumentationen: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

Konfiguration af PostgreSQL

For at arkiveren inde i databasen kan uploade WAL-logfiler til skyen og gendanne dem fra dem (om nødvendigt), skal du indstille flere parametre i konfigurationsfilen /etc/postgresql/12/main/postgresql.conf. Bare til at starte med du skal sikre digat ingen af ​​indstillingerne nedenfor er sat til andre værdier, så når konfigurationen genindlæses, går DBMS ikke ned. Du kan tilføje disse parametre ved at bruge:

#!/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 af de parametre, der skal indstilles:

  • wal_niveau – hvor meget information der skal skrives i WAL logs, “replika” – skriv alt;
  • arkivtilstand – aktiver download af WAL-logfiler ved hjælp af kommandoen fra parameteren arkiv_kommando;
  • arkiv_kommando – kommando til arkivering af en fuldført WAL-log;
  • arkiv_timeout – arkivering af logs udføres først, når den er afsluttet, men hvis din server ændrer/føjer lidt data til databasen, så giver det mening at sætte en grænse her i sekunder, hvorefter arkiveringskommandoen vil blive kaldt med magt (Jeg skriver intensivt til databasen hvert sekund, så jeg besluttede ikke at sætte denne parameter i produktion);
  • gendan_kommando – kommandoen til at gendanne WAL-loggen fra en sikkerhedskopi vil blive brugt, hvis "fuld backup" (basis backup) mangler de seneste ændringer i databasen.

Du kan læse mere om alle disse parametre i oversættelsen af ​​den officielle dokumentation: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Opsætning af en backup tidsplan

Uanset hvad man kan sige, er den mest bekvemme måde at køre det på cron. Dette er, hvad vi vil konfigurere til at oprette sikkerhedskopier. Lad os starte med kommandoen for at oprette en fuld sikkerhedskopi: i wal-g er dette startargumentet backup-push. Men først er det bedre at køre denne kommando manuelt fra postgres-brugeren for at sikre, at alt er i orden (og der er ingen adgangsfejl):

#!/bin/bash

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

Startargumenterne angiver stien til databiblioteket - jeg minder dig om, at du kan finde ud af det ved at køre pg_lsclusters.

Hvis alt gik uden fejl, og dataene blev indlæst i S3-lageret, kan du derefter konfigurere periodisk lancering 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 eksempel starter backup-processen hver dag kl. 4:15.

Sletning af gamle sikkerhedskopier

Mest sandsynligt behøver du ikke at beholde absolut alle sikkerhedskopier fra mesozoikumtiden, så det vil være nyttigt med jævne mellemrum at "rydde op" i dit lager (både "fulde sikkerhedskopier" og WAL-logfiler). Det vil vi gøre gennem en cron-opgave:

#!/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 vil køre denne opgave hver dag kl. 6:30 og slette alt (fulde sikkerhedskopier, delta'er og WAL'er) undtagen kopier for de sidste 10 dage, men efterlade mindst én backup til angivet dato, således at ethvert punkt efter datoer blev inkluderet i PITR.

Gendanner fra en sikkerhedskopi

Det er ingen hemmelighed, at nøglen til en sund database er periodisk gendannelse og verifikation af integriteten af ​​dataene indeni. Jeg fortæller dig, hvordan du genopretter ved hjælp af WAL-G i dette afsnit, og vi vil tale om checks senere.

Det skal bemærkes separat at for at gendanne i et testmiljø (alt der ikke er produktion) skal du bruge en Read Only-konto i S3 for ikke ved et uheld at overskrive sikkerhedskopier. I tilfælde af WAL-G skal du indstille følgende rettigheder for S3-brugeren i gruppepolitik (Effekt: Tillad): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. Og, selvfølgelig, glem ikke at indstille archive_mode=fra i indstillingsfilen postgresql.conf, så din testdatabase ikke ønsker at blive sikkerhedskopieret stille og roligt.

Restaurering udføres med en let bevægelse af hånden sletning af alle PostgreSQL-data (inklusive brugere), så vær yderst forsigtig, når du kø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 dem, der vil tjekke gendannelsesprocessen, er der udarbejdet et lille stykke bash-magi nedenfor, så i tilfælde af problemer med gendannelsen, vil scriptet gå ned med en exit-kode, der ikke er nul. I dette eksempel foretages 120 kontroller med en timeout på 5 sekunder (i alt 10 minutter til gendannelse) for at finde ud af, om signalfilen blev slettet (dette vil betyde, at gendannelsen lykkedes):

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

Efter vellykket gendannelse, glem ikke at starte alle processer tilbage (pgbouncer/monit osv.).

Kontrol af data efter gendannelse

Det er bydende nødvendigt at kontrollere databasens integritet efter gendannelse, så der ikke opstår en situation med en ødelagt/skæv backup. Og det er bedre at gøre dette med hvert oprettet arkiv, men hvor og hvordan afhænger kun af din fantasi (du kan hæve individuelle servere på timebasis eller køre en check i CI). Men som minimum er det nødvendigt at tjekke data og indekser i databasen.

For at kontrollere dataene er det nok at køre det gennem et dump, men det er bedre, at når du opretter databasen, har du kontrolsummer aktiveret (data kontrolsummer):

#!/bin/bash

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

For at kontrollere indekser - findes amcheck modul, lad os tage sql-forespørgslen til det fra WAL-G test og byg lidt logik omkring 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

sammenfattende

Jeg vil gerne udtrykke min taknemmelighed til Andrey Borodin for hans hjælp til at forberede publikationen og en særlig tak for hans bidrag til udviklingen af ​​WAL-G!

Dette afslutter denne note. Jeg håber, at jeg var i stand til at formidle den nemme opsætning og det enorme potentiale for at bruge dette værktøj i din virksomhed. Jeg hørte meget om WAL-G, men havde aldrig tid nok til at sætte mig ned og finde ud af det. Og efter at jeg implementerede det derhjemme, kom denne artikel ud af mig.

Separat er det værd at bemærke, at WAL-G også kan arbejde med følgende DBMS:

Kilde: www.habr.com

Tilføj en kommentar