WAL-G: Sicherungen und Wiederherstellung von PostgreSQL-DBMS

Es ist seit langem bekannt, dass die Erstellung von Backups in SQL-Dumps (mit pg_dump oder pg_dumpall) ist keine gute Idee. Um das PostgreSQL-DBMS zu sichern, ist es besser, den Befehl zu verwenden pg_basebackup, wodurch eine binäre Kopie der WAL-Protokolle erstellt wird. Aber wenn Sie beginnen, den gesamten Prozess der Erstellung einer Kopie und der Wiederherstellung zu studieren, werden Sie verstehen, dass Sie mindestens ein paar Dreiräder schreiben müssen, damit dies funktioniert und Ihnen sowohl oben als auch unten keine Schmerzen bereitet. Um Leiden zu lindern, wurde WAL-G entwickelt.

WAL-G ist ein in Go geschriebenes Tool zum Sichern und Wiederherstellen von PostgreSQL-Datenbanken (und in jüngerer Zeit MySQL/MariaDB, MongoDB und FoundationDB). Es unterstützt die Arbeit mit Amazon S3-Speicher (und Analoga, zum Beispiel Yandex Object Storage) sowie Google Cloud Storage, Azure Storage, Swift Object Storage und einfach mit dem Dateisystem. Die gesamte Einrichtung besteht aus einfachen Schritten, aber aufgrund der Tatsache, dass Artikel darüber im Internet verstreut sind, gibt es keine vollständige Anleitung, die alle Schritte von Anfang bis Ende umfassen würde (es gibt mehrere Beiträge auf Habré, aber da fehlen viele Punkte).

WAL-G: Sicherungen und Wiederherstellung von PostgreSQL-DBMS

Dieser Artikel wurde in erster Linie geschrieben, um mein Wissen zu systematisieren. Ich bin kein DBA und kann mich irgendwo in einer Laiensprache ausdrücken, daher sind Korrekturen willkommen!

Unabhängig davon stelle ich fest, dass alles Folgende für PostgreSQL 12.3 unter Ubuntu 18.04 relevant und getestet ist. Alle Befehle müssen als privilegierter Benutzer ausgeführt werden.

Einstellung

Zum Zeitpunkt des Schreibens dieses Artikels ist die stabile Version von WAL-G v0.2.15 (März 2020). Dies ist, was wir verwenden werden (Wenn Sie es jedoch selbst aus dem Master-Zweig erstellen möchten, finden Sie im Github-Repository alle Anweisungen dafür). Zum Herunterladen und Installieren müssen Sie Folgendes tun:

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

Danach müssen Sie zuerst WAL-G und dann PostgreSQL selbst konfigurieren.

WAL-G einrichten

Als Beispiel für die Speicherung von Backups wird Amazon S3 verwendet (weil es näher an meinen Servern liegt und seine Nutzung sehr günstig ist). Um damit arbeiten zu können, benötigen Sie einen „s3-Bucket“ und Zugriffsschlüssel.

In allen vorherigen Artikeln zu WAL-G wurde die Konfiguration mithilfe von Umgebungsvariablen verwendet, aber mit dieser Version können die Einstellungen in gefunden werden .walg.json-Datei im Home-Verzeichnis des Postgres-Benutzers. Führen Sie zum Erstellen das folgende Bash-Skript aus:

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

Lassen Sie mich alle Parameter kurz erklären:

  • WALG_S3_PREFIX – der Pfad zu Ihrem S3-Bucket, in den Backups hochgeladen werden (entweder ins Stammverzeichnis oder in einen Ordner);
  • AWS_ACCESS_KEY_ID – Zugangsschlüssel in S3 (Im Falle einer Wiederherstellung auf einem Testserver müssen diese Schlüssel über eine ReadOnly-Richtlinie verfügen! Dies wird im Abschnitt zur Wiederherstellung ausführlicher beschrieben.);
  • AWS_SECRET_ACCESS_KEY – geheimer Schlüssel im S3-Speicher;
  • WALG_COMPRESSION_METHOD – Komprimierungsmethode, es ist besser, Brotli zu verwenden (da dies das goldene Mittel zwischen der endgültigen Größe und der Komprimierungs-/Dekomprimierungsgeschwindigkeit ist);
  • WALG_DELTA_MAX_STEPS – die Anzahl der „Deltas“ vor der Erstellung einer Vollsicherung (sie sparen Zeit und die Größe der heruntergeladenen Daten, können aber den Wiederherstellungsprozess etwas verlangsamen, daher ist es nicht ratsam, große Werte zu verwenden);
  • PGDATEN – Pfad zum Verzeichnis mit Ihren Datenbankdaten (Sie können dies herausfinden, indem Sie den Befehl ausführen pg_lsclusters);
  • PGHOST – Verbindung zur Datenbank herstellen, bei einem lokalen Backup ist es besser, dies über einen Unix-Socket zu tun, wie in diesem Beispiel.

Weitere Parameter finden Sie in der Dokumentation: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

PostgreSQL konfigurieren

Damit der Archivierer in der Datenbank WAL-Protokolle in die Cloud hochladen und von dort wiederherstellen kann (falls erforderlich), müssen Sie mehrere Parameter in der Konfigurationsdatei festlegen /etc/postgresql/12/main/postgresql.conf. Nur für den Anfang Sie müssen sicherstellenStellen Sie sicher, dass keine der folgenden Einstellungen auf andere Werte gesetzt ist, damit das DBMS beim erneuten Laden der Konfiguration nicht abstürzt. Sie können diese Parameter hinzufügen mit:

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

Beschreibung der einzustellenden Parameter:

  • wal_level – wie viele Informationen in WAL-Protokolle geschrieben werden sollen, „Replikat“ – alles schreiben;
  • archive_mode – Aktivieren Sie das Herunterladen von WAL-Protokollen mit dem Befehl aus dem Parameter archive_command;
  • archive_command – Befehl zum Archivieren eines abgeschlossenen WAL-Protokolls;
  • archive_timeout – Die Archivierung von Protokollen wird erst durchgeführt, wenn sie abgeschlossen ist. Wenn Ihr Server jedoch nur wenige Daten zur Datenbank ändert/hinzufügt, ist es sinnvoll, hier ein Limit in Sekunden festzulegen, nach dem der Archivierungsbefehl zwangsweise aufgerufen wird (Da ich jede Sekunde intensiv in die Datenbank schreibe, habe ich beschlossen, diesen Parameter in der Produktion nicht festzulegen);
  • Wiederherstellungsbefehl – Der Befehl zum Wiederherstellen des WAL-Protokolls aus einem Backup wird verwendet, wenn im „vollständigen Backup“ (Basis-Backup) die neuesten Änderungen in der Datenbank fehlen.

Weitere Informationen zu all diesen Parametern finden Sie in der Übersetzung der offiziellen Dokumentation: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Einrichten eines Backup-Zeitplans

Was auch immer man sagen mag, die bequemste Art, es auszuführen, ist cron. Dies ist, was wir konfigurieren, um Backups zu erstellen. Beginnen wir mit dem Befehl zum Erstellen einer vollständigen Sicherung: In wal-g ist dies das Startargument Backup-Push. Aber zuerst ist es besser, diesen Befehl manuell vom Postgres-Benutzer auszuführen, um sicherzustellen, dass alles in Ordnung ist (und keine Zugriffsfehler vorliegen):

#!/bin/bash

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

Die Startargumente geben den Pfad zum Datenverzeichnis an – ich erinnere Sie daran, dass Sie ihn durch Ausführen herausfinden können pg_lsclusters.

Wenn alles ohne Fehler gelaufen ist und die Daten in den S3-Speicher geladen wurden, können Sie anschließend den periodischen Start in crontab konfigurieren:

#!/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 diesem Beispiel beginnt der Backup-Prozess jeden Tag um 4:15 Uhr.

Alte Backups löschen

Höchstwahrscheinlich müssen Sie nicht unbedingt alle Backups aus dem Mesozoikum aufbewahren, daher ist es sinnvoll, Ihren Speicher regelmäßig zu „bereinigen“ (sowohl „vollständige Backups“ als auch WAL-Protokolle). Wir werden dies alles durch eine Cron-Aufgabe erledigen:

#!/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 führt diese Aufgabe jeden Tag um 6:30 Uhr aus und löscht dabei alles (vollständige Backups, Deltas und WALs) mit Ausnahme der Kopien der letzten 10 Tage, hinterlässt aber mindestens ein Backup auf angegebenen Datum, so dass jeder Punkt nach Daten wurden in PITR aufgenommen.

Wiederherstellung aus einem Backup

Es ist kein Geheimnis, dass der Schlüssel zu einer gesunden Datenbank in der regelmäßigen Wiederherstellung und Überprüfung der Integrität der darin enthaltenen Daten liegt. In diesem Abschnitt erkläre ich Ihnen, wie Sie mit WAL-G eine Wiederherstellung durchführen, und wir werden später über Überprüfungen sprechen.

Separat erwähnenswert dass Sie zum Wiederherstellen in einer Testumgebung (alles, was nicht in der Produktion ist) ein schreibgeschütztes Konto in S3 verwenden müssen, um nicht versehentlich Sicherungen zu überschreiben. Im Fall von WAL-G müssen Sie in der Gruppenrichtlinie die folgenden Rechte für den S3-Benutzer festlegen (Wirkung: Erlauben): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. Und vergessen Sie natürlich nicht, es einzustellen archive_mode=aus in der Einstellungsdatei postgresql.conf, damit Ihre Testdatenbank nicht stillschweigend gesichert werden möchte.

Die Wiederherstellung erfolgt mit einer leichten Handbewegung Löschen aller PostgreSQL-Daten (einschließlich Benutzer), seien Sie daher bitte äußerst vorsichtig, wenn Sie die folgenden Befehle ausführen.

#!/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 diejenigen, die den Wiederherstellungsprozess überprüfen möchten, wurde unten ein kleines Stück Bash-Magie vorbereitet, damit das Skript bei Problemen bei der Wiederherstellung mit einem Exit-Code ungleich Null abstürzt. In diesem Beispiel werden 120 Prüfungen mit einem Timeout von 5 Sekunden (insgesamt 10 Minuten für die Wiederherstellung) durchgeführt, um herauszufinden, ob die Signaldatei gelöscht wurde (dies bedeutet, dass die Wiederherstellung erfolgreich war):

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

Vergessen Sie nach erfolgreicher Wiederherstellung nicht, alle Prozesse erneut zu starten (pgbouncer/monit usw.).

Überprüfung der Daten nach der Wiederherstellung

Es ist unbedingt erforderlich, die Integrität der Datenbank nach der Wiederherstellung zu überprüfen, damit es nicht zu einer Situation mit einem kaputten/krummen Backup kommt. Und es ist besser, dies mit jedem erstellten Archiv zu tun, aber wo und wie hängt nur von Ihrer Vorstellungskraft ab (Sie können einzelne Server stündlich hochfahren oder einen CI-Check durchführen). Es ist jedoch mindestens erforderlich, die Daten und Indizes in der Datenbank zu überprüfen.

Um die Daten zu überprüfen, reicht es aus, sie durch einen Dump laufen zu lassen. Es ist jedoch besser, wenn Sie beim Erstellen der Datenbank Prüfsummen aktiviert haben (Datenprüfsummen):

#!/bin/bash

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

Um Indizes zu überprüfen - vorhanden amcheck-Modul, nehmen wir die SQL-Abfrage dafür WAL-G-Tests und bauen Sie eine kleine Logik darauf auf:

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

zusammenfassend

Ich möchte Andrey Borodin meinen Dank für seine Hilfe bei der Vorbereitung der Veröffentlichung und insbesondere seinen Beitrag zur Entwicklung von WAL-G aussprechen!

Damit ist dieser Hinweis abgeschlossen. Ich hoffe, dass ich die einfache Einrichtung und das große Potenzial für den Einsatz dieses Tools in Ihrem Unternehmen vermitteln konnte. Ich habe viel über WAL-G gehört, hatte aber nie genug Zeit, mich hinzusetzen und es herauszufinden. Und nachdem ich es zu Hause umgesetzt hatte, kam dieser Artikel aus mir heraus.

Unabhängig davon ist anzumerken, dass WAL-G auch mit dem folgenden DBMS arbeiten kann:

Source: habr.com

Kommentar hinzufügen