WAL-G: PostgreSQL DBMS のバックアップとリカバリ

バックアップを SQL ダンプに作成することは長い間知られていました ( pg_dump または pg_dumpall)は良い考えではありません。 PostgreSQL DBMS をバックアップするには、次のコマンドを使用することをお勧めします。 pg_basebackup、WAL ログのバイナリ コピーを作成します。 しかし、コピーの作成と復元のプロセス全体を学習し始めると、すべてを機能させ、上面と下面の両方に苦痛を与えないようにするには、少なくとも XNUMX つの XNUMX つのサイクルを作成する必要があることがわかります。 その苦しみを軽減するために開発されたのがWAL-Gです。

WAL-G Go で書かれた、PostgreSQL データベースのバックアップと復元を行うツールです (最近では MySQL/MariaDB、MongoDB、FoundationDB)。 Amazon S3 ストレージ (および類似品、Yandex Object Storage)、Google Cloud Storage、Azure Storage、Swift Object Storage、および単純なファイル システムとの連携をサポートします。 セットアップ全体は簡単な手順で完了しますが、それに関する記事がインターネット上に散在しているため、最初から最後まですべての手順を含む完全なハウツー マニュアルはありません (Habré にはいくつかの投稿があります。しかし、そこでは多くの点が失われています)。

WAL-G: PostgreSQL DBMS のバックアップとリカバリ

この記事は主に私の知識を体系化するために書きました。 私は DBA ではありませんので、素人言葉で表現できるので、修正は大歓迎です。

これとは別に、以下の内容はすべて Ubuntu 12.3 上の PostgreSQL 18.04 に関連しており、テストされていることに注意してください。すべてのコマンドは特権ユーザーとして実行する必要があります。

インストール

この記事の執筆時点では、WAL-G の安定版は次のとおりです。 v0.2.15 (2020 年 XNUMX 月)。 これを使用します (ただし、master ブランチから自分でビルドする場合は、github リポジトリにそのためのすべての手順が含まれています。)。 ダウンロードしてインストールするには、次のことを行う必要があります。

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

この後、最初に WAL-G を構成し、次に PostgreSQL 自体を構成する必要があります。

WAL-Gのセットアップ

バックアップを保存する例として、Amazon S3 が使用されます (それは私のサーバーに近く、使用料が非常に安いためです)。 これを使用するには、「s3 バケット」とアクセス キーが必要です。

WAL-G に関するこれまでの記事はすべて、環境変数を使用した構成を使用していましたが、このリリースでは設定を次の場所に配置できます。 .walg.json ファイル postgres ユーザーのホーム ディレクトリ内。 これを作成するには、次の bash スクリプトを実行します。

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

すべてのパラメータについて少し説明しましょう。

  • WALG_S3_PREFIX – バックアップがアップロードされる S3 バケットへのパス (ルートまたはフォルダーのいずれかに指定できます)。
  • AWS_ACCESS_KEY_ID – S3 のアクセスキー (テスト サーバーでリカバリする場合、これらのキーには読み取り専用ポリシーが必要です。 これについては、回復に関するセクションで詳しく説明します。);
  • AWS_SECRET_ACCESS_KEY – S3 ストレージ内の秘密キー。
  • WALG_COMPRESSION_METHOD – 圧縮方法は、Brotli を使用することをお勧めします (これは、最終的なサイズと圧縮/解凍速度の黄金比であるため)。
  • WALG_DELTA_MAX_STEPS – 完全バックアップを作成する前の「デルタ」の数 (時間とダウンロードされるデータのサイズが節約されますが、回復プロセスがわずかに遅くなる可能性があるため、大きな値を使用することはお勧めできません)。
  • PGD​​ATA – データベース データが含まれるディレクトリへのパス (コマンドを実行するとわかります pg_lsclusters);
  • ゴースト – データベースに接続する場合、ローカル バックアップでは、この例のように unix-socket 経由で接続することをお勧めします。

他のパラメータはドキュメントにあります。 https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

PostgreSQL の構成

データベース内のアーカイバが WAL ログをクラウドにアップロードし、(必要に応じて) そこから復元できるようにするには、構成ファイルでいくつかのパラメータを設定する必要があります。 /etc/postgresql/12/main/postgresql.conf。 初心者向けに 確認する必要があります構成がリロードされたときに DBMS がクラッシュしないように、以下の設定はいずれも他の値に設定されていないことを確認してください。 以下を使用してこれらのパラメータを追加できます。

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

設定するパラメータの説明:

  • wal_level – WAL ログに書き込む情報量、「レプリカ」 – すべてを書き込みます。
  • アーカイブモード – パラメータからのコマンドを使用して、WAL ログのダウンロードを有効にします アーカイブコマンド;
  • アーカイブコマンド – 完了した WAL ログをアーカイブするためのコマンド。
  • アーカイブタイムアウト – ログのアーカイブは完了時にのみ実行されますが、サーバーがデータベースに少しのデータを変更/追加する場合は、ここで秒単位で制限を設定するのが合理的です。その後、アーカイブ コマンドが強制的に呼び出されます (私はデータベースに毎秒集中的に書き込むため、運用環境ではこのパラメータを設定しないことにしました。);
  • 復元コマンド – 「完全バックアップ」(ベース バックアップ)にデータベースの最新の変更が欠けている場合、バックアップから WAL ログを復元するコマンドが使用されます。

これらすべてのパラメータの詳細については、公式ドキュメントの翻訳を参照してください。 https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

バックアップスケジュールの設定

誰が何と言おうと、それを実行する最も便利な方法は cron です。 これは、バックアップを作成するために構成するものです。 完全バックアップを作成するコマンドから始めましょう。wal-g では、これは起動引数です。 バックアッププッシュ。 ただし、最初に、postgres ユーザーからこのコマンドを手動で実行して、すべてが正常である (アクセス エラーがない) ことを確認することをお勧めします。

#!/bin/bash

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

起動引数はデータ ディレクトリへのパスを示します。これは、次のコマンドを実行すると確認できることを思い出してください。 pg_lsclusters.

すべてがエラーなく完了し、データが S3 ストレージにロードされた場合は、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

この例では、バックアップ プロセスは毎日午前 4 時 15 分に開始されます。

古いバックアップの削除

おそらく、中生代のすべてのバックアップを完全に保持する必要はないため、ストレージ (「フル バックアップ」と WAL ログの両方) を定期的に「クリーンアップ」すると便利です。 これはすべて cron タスクを通じて行います。

#!/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 は毎日午前 6 時 30 分にこのタスクを実行し、過去 10 日間のコピーを除くすべて (完全バックアップ、差分、および WAL) を削除しますが、少なくとも XNUMX つのバックアップは残します。 до 指定日なのでどの時点でも 後の 日付はPITRに含まれていました。

バックアップからの復元

健全なデータベースの鍵は、定期的な復元と内部データの整合性の検証であることは周知の事実です。 このセクションでは、WAL-G を使用して回復する方法を説明し、チェックについては後ほど説明します。

別に注目に値する テスト環境 (本番環境ではないものすべて) で復元するには、バックアップを誤って上書きしないように、S3 で読み取り専用アカウントを使用する必要があります。 WAL-G の場合、グループ ポリシーで S3 ユーザーに次の権限を設定する必要があります (効果: 許可): s3:GetObject, s3:リストバケット, s3:GetBucketLocation。 そしてもちろん設定も忘れずに アーカイブモード=オフ 設定ファイル内で postgresql.conf、テスト データベースが静かにバックアップされることを望まないようにします。

復元は手のわずかな動きで実行されます すべての PostgreSQL データを削除する (ユーザーを含む) ため、次のコマンドを実行する場合は十分に注意してください。

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

回復プロセスを確認したい人のために、回復中に問題が発生した場合にスクリプトがゼロ以外の終了コードでクラッシュするように、小さな bash マジックが以下に用意されています。 この例では、信号ファイルが削除されたかどうかを確認するために、タイムアウトを 120 秒にして 5 回のチェックが行われます (回復には合計 10 分かかります) (これは回復が成功したことを意味します)。

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

正常に回復したら、すべてのプロセス (pgbouncer/monit など) を忘れずに再起動してください。

リカバリ後のデータ確認

バックアップが壊れたり歪んだりする事態が発生しないように、復元後にデータベースの整合性をチェックすることが不可欠です。 そして、作成されたアーカイブごとにこれを行う方が良いですが、どこでどのように行うかは想像力にのみ依存します (時間ごとに個々のサーバーを立ち上げたり、CI でチェックを実行したりすることができます)。 ただし、少なくともデータベース内のデータとインデックスを確認する必要があります。

データをチェックするには、ダンプを実行するだけで十分ですが、データベースの作成時にチェックサムを有効にしておく方が良いでしょう (データチェックサム):

#!/bin/bash

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

インデックスを確認するには - 存在します amcheckモジュールからSQLクエリを取得しましょう。 WAL-G テスト そしてそれを中心にちょっとしたロジックを構築します。

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

要約する

出版物の準備に協力してくれた Andrey Borodin に感謝の意を表したいと思います。また、WAL-G の開発への貢献に特別な感謝を表したいと思います。

これでこのメモは終わります。 セットアップの簡単さと、このツールを貴社で使用することによる大きな可能性をお伝えできれば幸いです。 WAL-G についてはよく聞いていましたが、じっくりと理解する時間がありませんでした。 そして、それを家で実践した後、この記事が出てきました。

これとは別に、WAL-G は次の DBMS とも連携できることに注意してください。

出所: habr.com

コメントを追加します