WAL-G: säkerhetskopior och återställning av PostgreSQL-databaser

Det är välkänt att göra säkerhetskopior i SQL-dumpar (använder pg_dump eller pg_dumpall) – är inte den bästa idén. För säkerhetskopiering av PostgreSQL-databaser är det bäst att använda kommandot pg_basebackup, som tar en binär kopia av WAL-loggarna. Men när du börjar studera hela processen för att skapa en kopia och återställa den, inser du att du måste skriva minst ett par trehjuliga cyklar för att allt ska fungera och inte orsaka smärta både uppe och nere. För att underlätta lidandet utvecklades WAL-G.

WAL-G – är ett verktyg skrivet i Go för säkerhetskopiering och återställning av PostgreSQL-databaser (och nyligen även MySQL/MariaDB, MongoDB och FoundationDB). Det stöder arbete med lagringslösningar som Amazon S3 (och liknande, som Yandex Object Storage), samt Google Cloud Storage, Azure Storage, Swift Object Storage och helt enkelt filsystemet. Hela konfigurationen består av enkla steg, men eftersom artiklar om det är spridda på internet – finns det ingen komplett how-to-manual som täcker alla steg från början till slut (det finns några inlägg på Habré, men många aspekter där har utelämnats).

WAL-G: säkerhetskopior och återställning av PostgreSQL-databaser

Denna artikel är skrivna främst för att systematisera mina kunskaper. Jag är inte DBA och kan uttrycka mig mer som en utvecklare, så alla rättelser är välkomna!

Jag vill särskilt påpeka att allt som anges nedan är aktuellt och testat för PostgreSQL 12.3 på Ubuntu 18.04, och alla kommandon bör köras av en privilegierad användare.

Installation

Vid tidpunkten för att skriva denna artikel är den stabila versionen av WAL-G – v0.2.15 (mars 2020). Det kommer vi att använda (men om du vill bygga det själv från master-grenen, finns det alla instruktioner för det i arkivet på github). För att ladda ner och installera behöver du köra:

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

Efter detta behöver du konfigurera först WAL-G och sedan PostgreSQL.

Konfigurering av WAL-G

För exemplet kommer lagring av säkerhetskopior att använda Amazon S3 (eftersom det ligger närmare mina servrar och dess användning är mycket billig). För att arbeta med det behövs en 's3-bucket' och accessnycklar.

I alla tidigare artiklar om WAL-G har konfigureringen gjorts via miljövariabler, men från och med denna version kan inställningarna placeras i .walg.json-filen i hemkatalogen för användaren postgres. För att skapa den kör vi följande 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

Låt mig förklara alla parametrar:

  • WALG_S3_PREFIX – sökvägen till din S3-bucket där säkerhetskopior kommer att laddas upp (kan vara antingen i roten eller en mapp);
  • AWS_ACCESS_KEY_ID – åtkomstnyckel till S3 (vid återställning på en testserver – dessa nycklar måste ha ReadOnly Policy! Mer information finns i avsnittet om återställning);
  • AWS_SECRET_ACCESS_KEY – hemlig nyckel i S3-lagringen;
  • WALG_COMPRESSION_METHOD – komprimeringsmetod, det är bäst att använda Brotli (eftersom det är en bra balans mellan slutstorlek och hastighet för komprimering/uppackning);
  • WALG_DELTA_MAX_STEPS – antal "delta" innan en fullständig säkerhetskopiering skapas (de sparar tid och storlek på de data som laddas upp, men kan sakta ner återställningsprocessen något, så stora värden bör undvikas);
  • PGDATA – sökväg till katalogen med dina databasdata (kan tas reda på genom att köra kommandot pg_lsclusters);
  • PGHOST – anslutning till databasen, vid lokal säkerhetskopiering är det bäst att göra det via unix-socket, som i det här exemplet.

De andra parametrarna kan ses i dokumentationen: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

Inställning av PostgreSQL

För att arkiveraren inuti databasen ska kunna ladda upp WAL-loggar till molnet och återskapa sig själv (vid behov) – måste du ställa in några parametrar i konfigurationsfilen /etc/postgresql/12/main/postgresql.conf. Men först måste du säkerställa, att inga av de nedan angivna inställningarna är satta till andra värden, så att när konfigurationen startas om – DBMS inte kraschar. Dessa parametrar kan läggas till med hjälp av:

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

Beskrivning av de inställda parametrarna:

  • wal_level – hur mycket information som ska skrivas i WAL-loggarna, "replica" – skriv allt;
  • archive_mode – aktivering av uppladdning av WAL-loggar med kommandot från parametern archive_command;
  • archive_command – kommando för att arkivera den slutförda WAL-loggen;
  • archive_timeout – arkivering av loggar sker endast när den är slutförd, men om din server sällan ändrar/lägger till data i databasen, kan det vara vettigt att sätta en tidsgräns i sekunder här, efter vilken arkiveringskommandot kommer att kallas tvingande (jag har intensiv skrivning till databasen varje sekund, så jag avstod från att sätta denna parameter i produktionen);
  • restore_command – kommando för att återställa WAL-loggen från säkerhetskopian, kommer att användas om "den fullständiga säkerhetskopian" (base backup) saknar de senaste ändringarna i databasen.

Mer om alla dessa parametrar kan läsas i översättningen av den officiella dokumentationen: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Konfiguration av säkerhetskopieringsschemat

Oavsett hur man vänder på det så är det smidigaste sättet att starta cron. Det är just detta vi kommer att konfigurera för att skapa säkerhetskopior. Vi börjar med kommandot för att skapa en fullständig backup: i wal-g är detta startargumentet. backup-push. Men det är bättre att först köra detta kommando manuellt som användaren postgres för att säkerställa att allt fungerar bra (och att det inte finns några åtkomstfel):

#!/bin/bash

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

I startargumenten anges sökvägen till katalogen med data – jag påminner om att du kan ta reda på den genom att köra pg_lsclusters.

Om allt gick utan fel och datan laddades upp till S3-lagringen, kan du sedan konfigurera en schemalagd körning 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 detta exempel startas backup-processen varje dag klockan 4:15 på morgonen.

Borttagning av gamla säkerhetskopior

Du behöver förmodligen inte lagra alla säkerhetskopior från mesozoikum, så det är bra att regelbundet "städa" ditt lagringsutrymme (både "fullständiga säkerhetskopior" och WAL-loggar). Vi kommer också att göra detta via en cron-uppgift:

#!/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 kommer att utföra denna uppgift varje dag klockan 6:30 på morgonen, och ta bort allt (fullständiga säkerhetskopior, deltar och WAL-loggar) utom kopior som är upp till 10 dagar gamla, men lämna minst en backup till från det angivna datumet så att varje punkt efter i tiden kan inkluderas i PITR.

Återställning från säkerhetskopian

Ingen hemlighet att en frisk databas beror på regelbunden återställning och kontroll av dataintegriteten. Hur man återställer med hjälp av WAL-G kommer jag att berätta i detta avsnitt, och vi pratar om kontroller senare.

Det bör noteras särskilt att för återställning i en testmiljö (allting som inte är produktion) – bör en Read Only-konto i S3 användas, så att säkerhetskopior inte oavsiktligt skrivs över. I fallet med WAL-G måste följande rättigheter ges till S3-användaren i Group Policy (Effect: Allow): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. Och naturligtvis, glöm inte att ställa in archive_mode=off i konfigurationsfilen postgresql.conf, så att din testdatabas inte oavsiktligt försöker att göra en backup tyst.

Återställning görs med ett enkelt handgrepp genom att ta bort all PostgreSQL-data (inklusive användare), så var vänlig och var extremt försiktig när du kör följande kommandon.

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

För dem som vill kontrollera återställningsprocessen har jag förberett ett litet stycke bash-magi nedan, så att skriptet faller med en icke-noll exitkod i händelse av problem med återställningen. I det här exemplet görs 120 kontroller med en timeout på 5 sekunder (totalt 10 minuter för återställning) för att ta reda på om signalfilen har tagits bort (detta betyder att återställningen har lyckats):

#!/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 en lyckad återställning, glöm inte att starta tillbaka alla processer (pgbouncer/monit osv).

Kontroll av data efter återställning

Det är absolut nödvändigt att kontrollera integriteten hos databasen efter återställningen, för att undvika situationer med korrupta eller skadade säkerhetskopior. Och det är bäst att göra detta med varje skapad arkiv, men var och hur beror endast på din fantasi (du kan starta separata servrar på timbasis eller köra kontroller i CI). Men som minimum – data och index i databasen måste kontrolleras.

För att kontrollera data är det tillräckligt att köra dem genom en dump, men det är bättre om kontrollsummor var aktiverade vid skapandet av databasen (data checksums):

#!/bin/bash

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

För att kontrollera index finns det amcheck-modulen, sql-frågan till den hämtar vi från WAL-G-tester och vi bygger upp en liten logik runt 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

Sammanfattningsvis

Jag vill tacka Andrej Borodin för hjälpen med att förbereda publikationen och särskilt för hans insats i utvecklingen av WAL-G!

Detta meddelande är nu slut. Jag hoppas att jag har lyckats förmedla enkelheten i inställningen och den stora potentialen för att använda detta verktyg i ditt företag. Jag har hört mycket om WAL-G, men hade aldrig tid att sätta mig ner och förstå. Efter att ha implementerat det själv kom denna artikel till.

Det är också värt att nämna att WAL-G också kan arbeta med följande DBMS:

Källa: habr.com

Köp pålitlig webbhotell med DDoS-skydd, VPS VDS-servrar 🔥 Köp pålitlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster