PostgreSQLスレーブ+ btrfsおよびsystemd =ホットテストベース



アクティブなソフトウェア開発では、戦闘ベースからの最新データを備えたテストベースが必要になることがよくあります。 ベースが小さく、コピーの展開に時間がかからない場合に適しています。 しかし、データベースに数十ギガバイトのデータがあり、完全なテストに必要なものすべて、さらに新しいものが必要な場合、問題が発生します。 この記事では、btrfsスナップショットを使用してこのような問題を解決するオプションについて説明します。 そして、結果として生じる複合体の仕事を管理するために、システム化されます-便利で機能的なツール。









準備する



サーバーでは、次を使用しました。
Debian jessie 4.7.0-0.bpo.1-amd64 #1 SMP Debian 4.7.8-1~bpo8+1 btrfs-progs v4.7.3 systemd 230 postgresql 9.6.1
      
      





しかし、これは重要ではありません。

ベースの下に表示されるbtrfsセクションで、2つのボリュームを作成します。







 btrfs subvolume create /var/lib/postgresql/slave btrfs subvolume create /var/lib/postgresql/snapshot
      
      





1つ目はデータベースデータを保存し、2つ目はこのデータのスナップショットを保存します。







まず、PostgreSQLスレーブデータベースを上げる必要があります。これには、通常モードではウィザードデータの完全なコピーが含まれます。 したがって、デプロイメントアルゴリズムは一度だけ説明されているわけではありません。







マスターpostgresql.conf
 max_wal_senders = 3 # max number of walsender processes # (change requires restart) wal_keep_segments = 64 # in logfile segments, 16MB each; 0 disables archive_mode = on # allows archiving to be done # (change requires restart) archive_command = 'test ! -f /var/lib/postgresql/9.6/main/archive/%f.7z && 7za a /var/lib/postgresql/9.6/main/archive/%f.7z -p______ -mx7 -mhe=on %p'
      
      





したがって、次のWALセグメントに入力した後、データベースフォルダ内の特別なアーカイブディレクトリにアーカイブするプロセスが開始されます。 私の場合、さらにこれらのアーカイブログは開いているチャネルによって送信され、別の場所にしばらく保存されるため、暗号化されパスワードで保護されます。 アーカイブログを保存する期間によって、ベーススレーブの状態を復元できる期間が決まります。 データベースへのアクティブな変更により、WALログの数は非常に急速に増加する可能性があるため、ここでは空き領域とアーカイブを使い果たすことが非常に便利です。







たとえば、次のように、アーカイブログを自分で消去する必要があります。







 find /var/lib/postgresql/9.6/main/archive/ -type f -mtime +10 -print0 | xargs -0 -n 13 /bin/rm
      
      





スレーブpostgresql.conf
 data_directory = '/var/lib/postgresql/slave/9.6/main' # use data in another directory hot_standby = on # "on" allows queries during recovery
      
      





/ var / lib / postgresqlはbtrfsセクションのマウントポイントであるため、データベースディレクトリを「 slave



」ディレクトリの標準ディレクトリより1レベル下に配置します。







スレーブrecovery.conf
 standby_mode = 'on' primary_conninfo = 'host=master.host port=5432 user=replicator password=' trigger_file = '/var/lib/postgresql/slave/9.6/main/trigger' restore_command = '7za e /mnt/backup/postgresql/archive/%f.7z -p______ -so > %p'
      
      





この設定では、データベースはスレーブモードで起動し、変更されたデータをウィザードから直接受け取ります。 ウィザードに突然データがなくなった場合、必要なデータセグメントがディレクトリ/ mnt / backup / postgresql / archive /から生成されます。 アーカイブログはrsyncを使用してそこに到達し、rsyncはウィザードから定期的に更新を取得します。 同期モードで削除して削除しますが、任意の期間保存できます。







また、データベースはトリガーファイルの外観を監視し、表示された場合はウィザードモードに切り替わり、すべての要求を単独で処理する準備が整います。 この瞬間から、マスターベースとスレーブベースは同期しなくなります。 そして、素晴らしいアイデアは、切り替える前にスレーブベースの写真を撮り、必要な実験の後、何も起こらなかったようにその場所に戻すことです。 上昇すると、ベースはマスターの背後にあることを発見し、アーカイブログを使用して追いつき、標準スレーブモードに入ります。 この操作は、バックアップからの完全復旧よりも大幅に短い時間で済みます。







systemdを使用してアイデアを実装します。これはプロセスを自動化するだけでなく、必要な依存関係と望ましくない競合も考慮します。 systemdがどのように機能し、どのように構成されているかについてはすでにご存じだと思いますが、使用するパラメーターについて詳しく説明していきます。







システム設定



まず、データベースデータが保存されているセクションをマウントします。 すべてをLXCコンテナにアセンブルします。btrfsを含むセクションは、パス/dev/pg-slave-test-db



沿ってブロックデバイスに入ります。 タイプ.mount



要素(ユニット)systemdを作成します。







/etc/systemd/system/var-lib-postgresql.mount
 [Unit] Description=PostgreSQL DB dir on BTRFS Conflicts=umount.target [Mount] What=/dev/pg-slave-test-db Where=/var/lib/postgresql Type=btrfs Options=defaults TimeoutSec=30 [Install] WantedBy=multi-user.target
      
      





アイテムの名前は、マウントポイントによって決まります。 Conflicts=umount.target



は、オフにされたときにパーティションがアンマウントされるようにします。 少し時間があります:絶対パスだけでなく、デバイスの一意のUUIDも使用できます。 しかし、LXCコンテナーで実行すると、奇妙なことに遭遇しました-システムのUUIDは、 blkid



コマンドによって明示的に要求されるまで表示されません。 したがって、絶対パスを使用します。







このユニットは独立して起動でき、依存関係で使用できます。







PostgreSQLがスレーブモードで起動する方法を記述するsystemd要素を作成します。 ベースは手動モードで起動するように事前設定されています/etc/postgresql/9.6/main/start.conf



では、これは/etc/postgresql/9.6/main/start.conf



ファイルで行われます。 また、 postgresql@9.6-main.service



サービスがある場合は、それをオフにする必要があります。







/etc/systemd/system/postgres-slave.service
 [Unit] Description=Restore PostgreSQL base snapshot and Switch the PostgreSQL base in slave mode. After=network.target var-lib-postgresql.mount postgresql.service Requires=var-lib-postgresql.mount Conflicts=postgres-master.service [Service] Type=oneshot RemainAfterExit=yes User=root TimeoutSec=300 ExecStartPre=-/usr/bin/pg_ctlcluster -m fast 9.6 main stop ExecStartPre=/bin/bash -c 'if [[ -d "/var/lib/postgresql/snapshot/auto" ]]; then /bin/btrfs subvolume delete /var/lib/postgresql/slave; fi' ExecStartPre=/bin/bash -c 'if [[ -d "/var/lib/postgresql/snapshot/auto" ]]; then /bin/mv -v /var/lib/postgresql/snapshot/auto /var/lib/postgresql/slave; fi' ExecStart=/usr/bin/pg_ctlcluster 9.6 main start ExecStop=/usr/bin/pg_ctlcluster -m fast 9.6 main stop [Install] WantedBy=multi-user.target
      
      





詳細に分析します。







After



パラメーターは、サービスを開始する目的のシーケンスを設定しますが、 Requires



とは異なり、何も強制しません。 後者では、指定されたサービスがアクティブである必要があり、アクティブにしようとします。 これが失敗すると、サービス全体が「 fail



」状態になります。 Conflicts



パラメーターは、サービスが指定されたサービスと共存できず、そのうちの1つをオフにする必要があることを示しています。 この場合、「 postgres-slave.service



」サービスが開始されると、「 "postgres-master.service



」(以下で説明します)が自動的にオフになります。これは非常に便利です。







Type=oneshot



は、このサービスが迅速に動作し、終了するまで待つ必要があることを意味します。 RemainAfterExit=yes



は、必要なアクションが正常に完了した後、サービスを「 active



」状態のままにします。 スナップショットを作成してデータベースを管理するため、タイムアウト(デフォルトでは30秒)を増やすことをお勧めします。







さらに、実際には、システムを目的の状態にするスクリプトが実行されます。 ExecStartPre



コマンドExecStartPre



、メインのExecStart



コマンドの前で順番に実行され、それぞれが前のコマンドExecStartPre



正常に完了するのを待っています。 ただし、最初のコマンドには修飾子「 - 」があり、戻りコードに関係なく実行を継続できます。 結局のところ、基地は打ち上げの時点ですでに停止している可能性があります。







起動時に実行されるスクリプト:
 /usr/bin/pg_ctlcluster -m fast 9.6 main stop /bin/bash -c 'if [[ -d "/var/lib/postgresql/snapshot/auto" ]]; then /bin/btrfs subvolume delete /var/lib/postgresql/slave; fi' /bin/bash -c 'if [[ -d "/var/lib/postgresql/snapshot/auto" ]]; then /bin/mv -v /var/lib/postgresql/snapshot/auto /var/lib/postgresql/slave; fi' /usr/bin/pg_ctlcluster 9.6 main start
      
      





プログラムへの絶対パスが必要です。 実行時にシステムの現在の状態を確認する必要がある場合、bashが呼び出され、小さなスクリプトが実行されます。 だから:







  1. 最初のステップでは、すべてのクライアントが切断するのを待たないように、「- -m fast



    」パラメーターを使用して作業データベースをオフにします。







  2. スレーブモードのデータベースの最後のスナップショットを保存し、「 postgres-master.service



    」サービスの結果として表示されるディレクトリ「 /var/lib/postgresql/snapshot/auto



    」があるかどうかを確認します。 スナップショットがある場合、データベースの現在の状態はマスターです。 テストデータベースデータ( /var/lib/postgresql/slave



    )を削除します。







  3. そして、この場所に写真を復元します。







  4. 準備チームが正常に完了した後、データベースを起動します。


最後の「 ExecStop



ExecStop



は、サービスのシャットダウン方法を決定します。 このサービスは自己完結型であり、システムの起動時に自動実行に追加できます。







PostgreSQLをマスターモードで起動する方法を説明するsystemd要素を作成します。







/etc/systemd/system/postgres-master.service
 [Unit] Description=Create PostgreSQL base Snapshot and Switch the PostgreSQL base in master mode. After=network.target var-lib-postgresql.mount postgresql.service Requires=var-lib-postgresql.mount Conflicts=postgres-slave.service [Service] Type=oneshot RemainAfterExit=yes User=root TimeoutSec=300 ExecStartPre=-/usr/bin/pg_ctlcluster -m fast 9.6 main stop ExecStartPre=/bin/bash -c 'if [[ -d "/var/lib/postgresql/snapshot/auto" ]]; then /sbin/btrfs subvolume delete /var/lib/postgresql/snapshot/auto; fi' ExecStartPre=/bin/btrfs subvolume snapshot /var/lib/postgresql/slave /var/lib/postgresql/snapshot/auto ExecStartPre=/usr/bin/touch /var/lib/postgresql/slave/9.6/main/trigger ExecStart=/usr/bin/pg_ctlcluster 9.6 main start ExecStop=/usr/bin/pg_ctlcluster -m fast 9.6 main stop [Install] WantedBy=multi-user.target
      
      





もちろん、サービスでの競合では、「 postgres-slave.service



」。







実行可能スクリプトは、次のように要約されます。
 /usr/bin/pg_ctlcluster -m fast 9.6 main stop /bin/bash -c 'if [[ -d "/var/lib/postgresql/snapshot/auto" ]]; then /sbin/btrfs subvolume delete /var/lib/postgresql/snapshot/auto; fi' /bin/btrfs subvolume snapshot /var/lib/postgresql/slave /var/lib/postgresql/snapshot/auto /usr/bin/touch /var/lib/postgresql/slave/9.6/main/trigger /usr/bin/pg_ctlcluster 9.6 main start
      
      





  1. 作業拠点を停止します。
  2. パス " /var/lib/postgresql/snapshot/auto



    "に沿って古いデータベーススナップショットがあるかどうかを確認し、ある場合は削除します。
  3. 最新のデータベースデータの新しいスナップショットを作成します。
  4. データベースをウィザードモードにするトリガーファイルを作成します。
  5. ベースを上げます。


これからは、データに対して最も大胆な実験を実行できます。 そして、あなたが疲れたら、「 postgres-slave.service



」サービスを実行すると、すべてが元の場所に戻ります。







データベースをさまざまなモードに切り替えるには、クラウン、特定の基準、依存サービスを使用するか、「. .socket



」タイプのsystemd要素を起動し、アプリケーションへの最初の要求時にテストベースを上げることもできます。 幸いなことに、systemdは許可します。







次のクエリを使用して、masterデータベースから現在のバックログを監視できます。







 postgres=# select now() - pg_last_xact_replay_timestamp() AS replication_delay;
      
      





同じzabbixを使用するのは難しくありません。







UPD pg_rewind



コメントは、btrfs自体の安定性に関する多くの懸念を提起し、特にデータベースを保存するためにそれを使用することの適合性について疑問を呈しています。 したがって、上記の概念をpg_rewindユーティリティの機能に適合させることを提案します。 このユーティリティは、マスターとスレーブの非同期ポイントを検出し、ターゲットベースを非同期前の最後の状態にします。 しかし、これは単なる状態であり、データを回復するには、すべての蓄積されたWALログが必要になります。 また、pg_rewindは、ベースがちょうど残っていても(私の場合は10G程度)、マスターからかなり大量のデータをダウンロードします。 また、ターゲットベースは、同期操作の前に操作を正しく完了する必要があります。







だから:







  1. テストベースの設定では、 wal_log_hints = on



    必要なwal_log_hints = on



    オプションを有効にする必要があり、パフォーマンスも低下する可能性があります。 マスターでは、テストサーバーからスーパーユーザー権限を持つユーザーへのアクセスを許可する必要があります。







  2. systemdスクリプトから、すべてのbtrfsを削除し、スナップショットを操作します。 「 postgres-master.service



    」は非常に単純になり、トリガーファイルの作成になります。







  3. スクリプト「 postgres-slave.service



    」は次のようになります。


/etc/systemd/system/postgres-slave.service
 [Unit] Description=Restore PostgreSQL base snapshot and Switch the PostgreSQL base in slave mode. After=network.target var-lib-postgresql.mount postgresql.service Requires=var-lib-postgresql.mount Conflicts=postgres-master.service [Service] Type=oneshot RemainAfterExit=yes User=root #     . TimeoutSec=300 ExecStartPre=-/usr/bin/pg_ctlcluster -m fast 9.6 main stop ExecStartPre=/bin/bash -c 'if [[ -e "/var/lib/postgresql/slave/9.6/main/recovery.done" ]]; then /usr/lib/postgresql/9.6/bin/pg_rewind -D /var/lib/postgresql/slave/9.6/main/ --source-server="host=master.host port=5432 user=postgres password=___" --progress ; /bin/cp /var/lib/postgresql/recovery.conf /var/lib/postgresql/slave/9.6/main/recovery.conf; fi' ExecStart=/usr/bin/pg_ctlcluster 9.6 main start ExecStop=/usr/bin/pg_ctlcluster -m fast 9.6 main stop [Install] WantedBy=multi-user.target
      
      





pg_rewind



開始する前に、データベースを正しくシャットダウンする必要があります。

データベースがマスター状態の場合、メインデータベースとの同期を開始します。







  1. ターゲットデータベースディレクトリ( -D



    )、マスターに接続するためのパラメーター、および詳細な出力キーを使用してpg_rewind



    を実行します。
  2. 以前に保存したrecovery.conf



    ファイルをコピーします。このファイルはpg_rewind



    結果として削除されます。
  3. WALログを使用して、エスケープされたマスターに追いつき始めるベースを上げます。


この場合、スレーブデータベースのリカバリにはかなり時間がかかりますが、btrfsを使用する危険はありません。







ご清聴ありがとうございました。








All Articles