WAL-G: back-ups en herstel van PostgreSQL DBMS

Het is al lang bekend dat het maken van back-ups in SQL-dumps (met behulp van pg_dump of pg_dumpall) is geen goed idee. Om een ​​back-up te maken van het PostgreSQL DBMS, is het beter om de opdracht te gebruiken pg_basebackup, dat een binaire kopie maakt van WAL-logboeken. Maar als je het hele proces van het maken van een kopie en het herstellen begint te bestuderen, zul je begrijpen dat je op zijn minst een paar driewielers moet schrijven om dit te laten werken en je zowel boven als onder geen pijn te bezorgen. Om het lijden te verlichten werd WAL-G ontwikkeld.

WAL-G is een tool geschreven in Go voor het maken van back-ups en het herstellen van PostgreSQL-databases (en meer recentelijk MySQL/MariaDB, MongoDB en FoundationDB). Het ondersteunt het werken met Amazon S3-opslag (en analogen, bijvoorbeeld Yandex Object Storage), evenals Google Cloud Storage, Azure Storage, Swift Object Storage en eenvoudig met het bestandssysteem. De hele installatie komt neer op eenvoudige stappen, maar vanwege het feit dat artikelen erover verspreid zijn over het internet, is er geen volledige handleiding die alle stappen van begin tot eind omvat (er zijn verschillende berichten op Habré, maar daar worden veel punten gemist).

WAL-G: back-ups en herstel van PostgreSQL DBMS

Dit artikel is in de eerste plaats geschreven om mijn kennis te systematiseren. Ik ben geen DBA en kan mij ergens in lekentaal uitdrukken, dus correcties zijn welkom!

Afzonderlijk merk ik op dat alles hieronder relevant en getest is voor PostgreSQL 12.3 op Ubuntu 18.04, alle opdrachten moeten worden uitgevoerd als een bevoorrechte gebruiker.

installatie

Op het moment dat dit artikel wordt geschreven, is de stabiele versie van WAL-G beschikbaar v0.2.15 (maart 2020). Dit is wat we zullen gebruiken (maar als je het zelf wilt bouwen vanuit de master branch, dan heeft de github repository hiervoor alle instructies). Om te downloaden en te installeren moet u het volgende doen:

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

Hierna moet u eerst WAL-G configureren en vervolgens PostgreSQL zelf.

WAL-G instellen

Voor een voorbeeld van het opslaan van back-ups wordt Amazon S3 gebruikt (omdat het dichter bij mijn servers ligt en het gebruik ervan erg goedkoop is). Om ermee te werken heb je een “s3-bucket” en toegangssleutels nodig.

Alle eerdere artikelen over WAL-G maakten gebruik van configuratie met behulp van omgevingsvariabelen, maar met deze release kunnen de instellingen worden gevonden in .walg.json-bestand in de homedirectory van de postgres-gebruiker. Om het te maken, voert u het volgende bash-script uit:

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

Laat me een beetje uitleggen over alle parameters:

  • WALG_S3_PREFIX – het pad naar uw S3-bucket waar back-ups worden geüpload (u kunt naar de root of naar een map);
  • AWS_ACCESS_KEY_ID – toegangssleutel in S3 (in geval van herstel op een testserver moeten deze sleutels een ReadOnly-beleid hebben! Dit wordt in meer detail beschreven in het hoofdstuk over herstel.);
  • AWS_SECRET_ACCESS_KEY – geheime sleutel in S3-opslag;
  • WALG_COMPRESSION_METHOD – compressiemethode, het is beter om Brotli te gebruiken (aangezien dit de gulden middenweg is tussen de uiteindelijke grootte en de compressie-/decompressiesnelheid);
  • WALG_DELTA_MAX_STEPS – het aantal “delta’s” voordat een volledige back-up wordt gemaakt (ze besparen tijd en de grootte van gedownloade gegevens, maar kunnen het herstelproces enigszins vertragen, dus het is niet aan te raden om grote waarden te gebruiken);
  • PGDATA – pad naar de map met uw databasegegevens (je kunt erachter komen door de opdracht uit te voeren pg_lclusters);
  • PGHOST – verbinding maken met de database, bij een lokale backup is het beter om dit via een unix-socket te doen zoals in dit voorbeeld.

Andere parameters zijn te vinden in de documentatie: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

PostgreSQL configureren

Om ervoor te zorgen dat de archiver in de database WAL-logboeken naar de cloud kan uploaden en ze daaruit kan herstellen (indien nodig), moet u verschillende parameters instellen in het configuratiebestand /etc/postgresql/12/main/postgresql.conf. Gewoon om te beginnen je moet het zeker wetendat geen van de onderstaande instellingen op andere waarden is ingesteld, zodat het DBMS niet crasht wanneer de configuratie opnieuw wordt geladen. U kunt deze parameters toevoegen met behulp van:

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

Beschrijving van de in te stellen parameters:

  • wal_niveau – hoeveel informatie er in WAL-logboeken moet worden geschreven, “replica” – schrijf alles;
  • archief_modus – schakel het downloaden van WAL-logboeken in met behulp van de opdracht van de parameter archief_commando;
  • archief_commando – opdracht voor het archiveren van een voltooid WAL-logboek;
  • archief_time-out – het archiveren van logs wordt pas uitgevoerd als het voltooid is, maar als uw server weinig gegevens aan de database wijzigt/voegt, dan is het zinvol om hier een limiet in te stellen in seconden, waarna het archiveringscommando met geweld wordt aangeroepen (Ik schrijf elke seconde intensief naar de database, dus besloot ik deze parameter niet in productie te zetten);
  • herstel_commando – de opdracht om het WAL-logboek te herstellen vanaf een back-up wordt gebruikt als de “volledige back-up” (basisback-up) de laatste wijzigingen in de database mist.

U kunt meer lezen over al deze parameters in de vertaling van de officiële documentatie: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Opstellen van een back-upschema

Wat je ook zegt, de handigste manier om het uit te voeren is cron. Dit is wat we zullen configureren om back-ups te maken. Laten we beginnen met het commando om een ​​volledige back-up te maken: in wal-g is dit het startargument back-up-push. Maar eerst is het beter om deze opdracht handmatig uit te voeren vanuit de postgres-gebruiker om er zeker van te zijn dat alles in orde is (en dat er geen toegangsfouten zijn):

#!/bin/bash

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

De startargumenten geven het pad naar de gegevensmap aan. Ik herinner u eraan dat u dit kunt achterhalen door te rennen pg_lclusters.

Als alles zonder fouten is verlopen en de gegevens in de S3-opslag zijn geladen, kunt u vervolgens de periodieke lancering in crontab configureren:

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

In dit voorbeeld begint het back-upproces elke dag om 4 uur.

Oude back-ups verwijderen

Hoogstwaarschijnlijk hoeft u niet absoluut alle back-ups uit het Mesozoïcum te bewaren, dus het zal handig zijn om uw opslag periodiek "op te schonen" (zowel "volledige back-ups" als WAL-logboeken). We doen dit allemaal via een cron-taak:

#!/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 voert deze taak elke dag om 6 uur uit, waarbij alles wordt verwijderd (volledige back-ups, delta's en WAL's) behalve kopieën van de afgelopen 30 dagen, maar er blijft minimaal één back-up over naar gespecificeerde datum zodat elk punt na data werden opgenomen in PITR.

Herstellen vanaf een back-up

Het is geen geheim dat de sleutel tot een gezonde database periodiek herstel en verificatie van de integriteit van de gegevens erin is. Ik zal je in deze sectie vertellen hoe je kunt herstellen met WAL-G, en we zullen het later over controles hebben.

Het moet apart worden vermeld dat u voor het herstellen in een testomgeving (alles wat geen productie is) een Read Only-account in S3 moet gebruiken om te voorkomen dat u per ongeluk back-ups overschrijft. In het geval van WAL-G moet u de volgende rechten instellen voor de S3-gebruiker in Groepsbeleid (Effect: toestaan): s3:GetObject, s3:Lijstbucket, s3: Haal BucketLocation op. En vergeet natuurlijk niet om in te stellen archive_mode=uit in het instellingenbestand postgresql.conf, zodat er niet stilletjes een back-up van uw testdatabase wil worden gemaakt.

Restauratie wordt uitgevoerd met een lichte beweging van de hand alle PostgreSQL-gegevens verwijderen (inclusief gebruikers), dus wees uiterst voorzichtig wanneer u de volgende opdrachten uitvoert.

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

Voor degenen die het herstelproces willen controleren, is hieronder een klein stukje bash-magie voorbereid, zodat in geval van problemen bij het herstel het script crasht met een exit-code die niet nul is. In dit voorbeeld worden 120 controles uitgevoerd met een time-out van 5 seconden (in totaal 10 minuten voor herstel) om erachter te komen of het signaalbestand is verwijderd (dit betekent dat het herstel succesvol was):

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

Vergeet na een succesvol herstel niet alle processen opnieuw te starten (pgbouncer/monit, enz.).

Gegevens controleren na herstel

Het is absoluut noodzakelijk om na het herstel de integriteit van de database te controleren, zodat er geen situatie met een kapotte/slechte back-up ontstaat. En het is beter om dit met elk gemaakt archief te doen, maar waar en hoe hangt alleen af ​​van uw verbeeldingskracht (u kunt individuele servers op uurbasis verhogen of een CI-check uitvoeren). Maar het is op zijn minst noodzakelijk om de gegevens en indexen in de database te controleren.

Om de gegevens te controleren is het voldoende om deze door een dump te laten lopen, maar het is beter dat u bij het maken van de database controlesommen hebt ingeschakeld (gegevenscontrolesommen):

#!/bin/bash

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

Indexen controleren - bestaat amcheck-module, laten we de SQL-query ervoor nemen WAL-G-testen en bouw er een beetje logica omheen:

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

Samenvattend

Ik wil graag mijn dank betuigen aan Andrey Borodin voor zijn hulp bij het voorbereiden van de publicatie en speciale dank voor zijn bijdrage aan de ontwikkeling van WAL-G!

Hiermee wordt deze notitie afgesloten. Ik hoop dat ik het installatiegemak en de enorme mogelijkheden voor het gebruik van deze tool in uw bedrijf heb kunnen overbrengen. Ik heb veel over WAL-G gehoord, maar heb nooit genoeg tijd gehad om er even voor te gaan zitten en het uit te zoeken. En nadat ik het thuis had geïmplementeerd, kwam dit artikel uit mij.

Daarnaast is het vermeldenswaard dat WAL-G ook kan werken met de volgende DBMS:

Bron: www.habr.com

Voeg een reactie