web-dev-qa-db-ja.com

PostgreSQLのリカバリ戦略は正確にどのように機能しますか?

私はPostgreSQL 11のバックアップとリカバリの戦略がどのように機能するかをテストして理解しようとしていますが、期待どおりに機能しません。バックアップをリカバリすると、正しい状態が得られません。与えられたタイムスタンプの後の状態を取得します。詳細に:

私はこのセットアップをデータベースに持っています:

_wal_level = replica 
max_wal_senders = 10
archive_mode = on
_

次のコマンドを実行しました。

_postgres=# select pg_create_physical_replication_slot('slot1');
pg_basebackup -D /media/extern/postgresql_basebackup/
pg_receivewal -D /media/extern/postgresql_archive -S slot1 -v
_

pg_receivewalはpostgresql_archiveに書き込んでいますが、これは動作するようです。

  • 次に、データベースに何かを挿入します。16:21にしましょう。
  • 数分待って、16:27までとし、すべての挿入を削除します。

次に、次のようにして挿入を回復したいと思います...

_service postgresql stop
_

(pg_receivewalも停止する必要がありますか?)

_# mv main main.before_recovery
# cp -rp /media/extern/postgresql_basebackup main

nano /var/lib/postgresql/11/main/recovery.conf
_

以下のコンテンツを追加します

_restore_command = 'cp -r /media/extern/postgresql_archive/%f %p'
recovery_target_time='2018-01-06 16:22:00'
_

それから私は実行します

_# chown postgres:postgres recovery.conf 
# chmod 700 recovery.conf 

service postgresql start
_

起動後、ファイルはrecovery.doneに変わりますが、データベースの状態が間違っています。データは復元されませんでした。データベースはまだ空なので、PITRは機能しませんでした。なぜですか?

回復後にすべてが成功した場合はどうすればよいですか?これらの質問についてはよくわかりません:

  • pg_create_physical_replication_slot( 'slot2');を実行して新しいスロット2を作成し、このスロットからpg_receivewal -D/media/extern/postgresql_archive -S slot2 -v
  • Pg_receivewal -D/media/extern/postgresql_archive -S slot1 -vをもう一度実行しますか?
  • Postgresql_archiveのデータを削除する必要がありますか? (->おそらくそうではない)
  • いつ別のベースバックアップを作成する必要がありますか?
  • いつ、なぜ私はselect pg_switch_wal();を実行するのですか?
  • 回復後の新しい「タイムライン」にはどのように対処しますか?タイムラインの概念は理解していますが、復旧後にどのように進めればよいかわかりません。

[更新]
jjanesさんは、日付が間違っていると指摘しました。修正しましたが、復旧後も空のデータベースが表示されます。空になったデータベースを回復した後、次の手順を試しました。

2019-01-08、18:50:この空のデータベースから新しいベースバックアップを作成して、出発点として適切です。

2019-01-08、18:55作成スロット1

pg_receivewal -D/media/extern/postgresql_archive -S slot1 -v

2019-01-08、18:57挿入

2019-01-08、19:38削除

サービスpostgresql停止

_# mv main main.before_recovery
# cp -rp /media/extern/postgresql_basebackup main
# chmod 700 main

# nano /var/lib/postgresql/11/main/recovery.conf

restore_command = 'cp -r /media/extern/postgresql_archive/%f %p'
recovery_target_time='2019-01-08 19:20:00'

# chown postgres:postgres recovery.conf 
# chmod 700 recovery.conf 

# service postgresql start
_

(ところで:私はそれが回復後にそれ自体で新しいタイムライムを開始するのを見ました。)

[更新]
postgresql.confでアクティブ化しました

_checkpoint_flush_after = 256kB 
checkpoint_timeout = 30s
_

以前の方法を使用してデータベースを復元しようとしましたが、なしrecovery_target_timeおよびなし DELETEステートメント。現在の完全な状態をまったく再構築できるかどうかを確認したかっただけです。さらに、データベースを停止した後、データを回復する前に、現在のwalファイル00000007000000000000002D.partialを00000007000000000000002Dに名前変更しました。

(空の)ベースバックアップとwalファイルをインストールすることで最新のデータを復元できたため、現在、これらのうちどれが機能したかはわかりませんが、PITR以外のリカバリは機能しているようです。少なくとも正しい方向への一歩ですが、これは出荷されたwalファイルを見逃していない場合にのみ機能します。ここで、質問2が始まります。「次の出荷の反復」を処理するための正しいワークフローは何ですか。最初は、_pg_receivewal -D /media/extern/postgresql_archive -S slot1 -v_を再度開始することはできませんなし外部フォルダー内の出荷されたWALを削除します。そうしないと、ログの送信が開始されず、接続エラーで中止されます。これは、古いベースバックアップを破棄できることを意味します。古いベースバックアップでリカバリを再試行すると、ベースバックアップと最後のリカバリポイントの間のすべてのwalログが失われるためです(それらを削除したため)。つまり、復旧ポイントの状態からすぐに新しいベースバックアップを作成する必要があります。ログ配布を再開すると、新しいベースバックアップとwalファイルの間に「ギャップ」がなくなります。

[更新]
PITRを同じアプローチで実行したので、削除を「取り消す」ことができました。リカバリおよび_service postgresql start_の後、データベースは読み取り専用モードのままになります。再びRWにするためにselect pg_wal_replay_resume();を実行する必要がありました。すでに述べたように、WAL配送を再度行うことはできません。アーカイブフォルダーを変更せず、WALを再起動して同じフォルダー内で出荷しようとすると、次の例外が発生します。

pg_receivewal:レプリケーションコマンド "START_REPLICATION"を送信できませんでした:エラー:タイムライン11で要求された開始点0/34000000はこのサーバーの履歴にありません詳細:このサーバーの履歴はタイムライン11からフォークされた0/3310ADA8です。

もちろん、新しいアーカイブフォルダーなどにログ配布を行うことはできますが、これはそのための専門的な方法ではないと思います。回復後にログ配布を再開するために一般的に使用される戦略は何ですか?

3
Bevor

次のガイドラインに従ってテストを行いました。

1) create a new base backup  
2) create slot  
3) launch pg_receivewal -D PATH -S slotname -v
4) delete records
5) postgresql stop / delete PGDATA
6) cp -rp postgresql_basebackup PGDATA
7) edit recovery.conf
   restore_command = 'cp -ir /PATH/%f %p'
   recovery_target_time=timestamp
8) postgresql start  

とPITRはアスペクトされたように働いた。コメントで私がしたことに従ってください。簡単なループで200行が作成されたdb(テスト)と1つのテーブルt1を作成した、新しいpostgresインストールがあります。目次:

postgres=# \c test
You are now connected to database "test" as user "postgres".
test=# \d t1
                    Table "public.t1"
 Column |         Type          | Collation | Nullable | Default
--------+-----------------------+-----------+----------+---------
 col1   | character varying(20) |           |          |

test=# select * from t1 limit 5;
 col1
-------
 1ABCD
 2ABCD
 3ABCD
 4ABCD
 5ABCD
(5 rows)

test=# select count(1) from t1;
count
-------
   200
(1 row)

ステップ1)、2)、3)

まず、クリーンな状況から始めます。

    postgres=# select now();
              now
-------------------------------
 2019-01-11 15:19:19.441022+01
(1 row)

postgres=# select * from pg_catalog.pg_replication_slots;
 slot_name | plugin | slot_type | datoid | database | temporary | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn
-----------+--------+-----------+--------+----------+-----------+--------+------------+------+--------------+-------------+---------------------
(0 rows)

postgres=# select pg_switch_wal();
 pg_switch_wal
---------------
 0/B000190
(1 row)

$ cd /PGDATA-11/pg_wal/
$ ls -lrt
total 32768
drwx------ 2 postgres postgres        6 Jan 11 15:15 archive_status
-rw------- 1 postgres postgres 16777216 Jan 11 15:20 000000010000000000000001
-rw------- 1 postgres postgres 16777216 Jan 11 15:20 000000010000000000000002

バックアップを作成します。

$ /usr/pgsql-11/bin/pg_basebackup -D /home/postgres/HOT-BACKUP/  

postgres=# select pg_create_physical_replication_slot('test1');  
pg_create_physical_replication_slot
-------------------------------------
 (test1,)
(1 row)  

$ /usr/pgsql-11/bin/pg_receivewal -D /home/postgres/BCK-PITR-TEST/ -S test1 -v -n &
[1] 23350
$ pg_receivewal: starting log streaming at 0/4000000 (timeline 1)

Pg_receivewallを "-n"で開始して、postgresサーバーがダウンしたときに停止するようにし、バックグラウンドに置きました。

$ ls -rlt /home/postgres/BCK-PITR-TEST/
total 16384
-rw------- 1 postgres postgres 16777216 Jan 11 15:29 000000010000000000000004.partial

ステップ4)

test=# select now();
          now
-------------------------------
 2019-01-11 15:31:24.201177+01
(1 row)

test=# select count(1) from t1 where col1 like ('1%');
 count
-------
   111
(1 row)

スリープ2分.........

test=# select now();
              now
-------------------------------
 2019-01-11 15:33:24.886394+01
(1 row)

test=# delete from t1 where col1 like '1%';
DELETE 111
test=#

ステップ5)

$ /usr/pgsql-11/bin/pg_ctl stop -D /PGDATA-11/  
waiting for server to shut down....pg_receivewal: not renaming "000000010000000000000004.partial", segment is not complete
pg_receivewal: replication stream was terminated before stop point
pg_receivewal: disconnected
 done
server stopped
[1]+  Exit 1                  /usr/pgsql-11/bin/pg_receivewal -D /home/postgres/BCK-PITR-TEST/ -S test1 -v -n

起動時のパラメータ「-n」が原因で、pg_receivewalがどのように停止するかに注意してください。
最新のWAL(XXX4)の内容を確認しましょう:

 $ /usr/pgsql-11/bin/pg_waldump 000000010000000000000004 000000010000000000000004
rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 0/04000028, prev 0/030000F8, desc: RUNNING_XACTS nextXid 572 latestCompletedXid 571 oldestRunningXid 572
rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 0/04000060, prev 0/04000028, desc: RUNNING_XACTS nextXid 572 latestCompletedXid 571 oldestRunningXid 572
rmgr: XLOG        len (rec/tot):    106/   106, tx:          0, lsn: 0/04000098, prev 0/04000060, desc: CHECKPOINT_ONLINE redo 0/4000060; tli 1; prev tli 1; fpw true; xid 0:572; oid 24576; multi 1; offset 0; oldest xid 561 in DB 1; oldest multi 1 in DB 1; oldest/newest commit timestamp xid: 0/0; oldest running xid 572; online
rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 0/04000108, prev 0/04000098, desc: RUNNING_XACTS nextXid 572 latestCompletedXid 571 oldestRunningXid 572
rmgr: Heap        len (rec/tot):     59/  7283, tx:        572, lsn: 0/04000140, prev 0/04000108, desc: DELETE off 1 KEYS_UPDATED , blkref #0: rel 1663/16384/16385 blk 0 FPW
rmgr: Heap        len (rec/tot):     54/    54, tx:        572, lsn: 0/04001DB8, prev 0/04000140, desc: DELETE off 10 KEYS_UPDATED , blkref #0: rel 1663/16384/16385 blk 0
rmgr: Heap        len (rec/tot):     54/    54, tx:        572, lsn: 0/04001DF0, prev 0/04001DB8, desc: DELETE off 11 KEYS_UPDATED , blkref #0: rel 1663/16384/16385 blk 0
...........................................................................................................................................................................
rmgr: Transaction len (rec/tot):     34/    34, tx:        572, lsn: 0/040035E0, prev 0/040035A8, desc: COMMIT 2019-01-11 15:33:31.342763 CET

最後の行で、削除のコミットタイムスタンプを確認できます:COMMIT 2019-01-11 15:33:31.342763 CET。これは、削除ステートメントを拒否するために到達する必要があるタイムスタンプです。したがって、recovery.confは、このタイムスタンプの前のタイムスタンプで編集されることがあります。
PGDATAを削除し、HOTバックアップパスからPGDATAにバックアップファイルを復元した後、recovery.confを編集してpostgresを再起動しました。

手順6)、7)、8):

$ cp -rp /home/postgres/HOT-BACKUP/* /PGDATA-11/
$ vi recovery.conf

$ cat recovery.conf
restore_command = 'cp -ir /home/postgres/BCK-PITR-TEST/%f %p'
recovery_target_time='2019-01-11 15:31:24.201177+01'

$ /usr/pgsql-11/bin/pg_ctl start -D /PGDATA-11/ &

サーバーログを見て、私は重要な行だけを残しました:

2019-01-11 15:56:46.873 CET [28768] LOG:  database system was interrupted; last known up at 2019-01-11 15:27:52 CET
2019-01-11 15:56:46.885 CET [28768] LOG:  starting point-in-time recovery to 2019-01-11 15:31:24.201177+01
2019-01-11 15:56:46.911 CET [28768] LOG:  redo starts at 0/3000028
2019-01-11 15:56:46.913 CET [28768] LOG:  consistent recovery state reached at 0/30000F8
2019-01-11 15:56:46.914 CET [28766] LOG:  database system is ready to accept read only connections
2019-01-11 15:56:46.931 CET [28768] LOG:  restored log file "000000010000000000000004" from archive
2019-01-11 15:56:46.951 CET [28768] LOG:  recovery stopping before commit of transaction 572, time 2019-01-11 15:33:31.342763+01
2019-01-11 15:56:46.951 CET [28768] LOG:  recovery has paused
2019-01-11 15:56:46.951 CET [28768] HINT:  Execute pg_wal_replay_resume() to continue.

WAlファイルXXX3にあるlsn 0/30000F8でリカバリプロセスが一貫した状態に達したことがわかります。WALXXX4はコピーされましたが、recovery.confで設定したタイムスタンプが原因で適用されませんでした。

もちろん、削除された行は現在dbに存在するので、pg_wal_replay_resume()を実行してdb RWを再度持ってきます。

test=# select count(1) from t1;
 count
-------
    200
(1 row)

test=# select pg_wal_replay_resume();
 pg_wal_replay_resume
----------------------

(1 row)

Walファイルがタイムライン2に移動しました。

$  ls -lrt
total 49156
-rw------- 1 postgres postgres 16777216 Jan 11 15:54 000000020000000000000005
-rw------- 1 postgres postgres 16777216 Jan 11 15:56 000000010000000000000004
drwx------ 2 postgres postgres       42 Jan 11 15:56 archive_status
-rw------- 1 postgres postgres       50 Jan 11 15:59 00000002.history
-rw------- 1 postgres postgres 16777216 Jan 11 15:59 000000020000000000000004

Pg_receivewalを組み込んだarchive_commandを使用して同様のテストを行い、同じ結果を得ました。 dbログをデバッグに入れて、pg_waldumpでWALファイルの内容を確認することをお勧めします。奇妙なことがあなたに起こっています、そして何が起こっているのかをキャッチするのは興味深いかもしれません。

この助けを願っています。 MarcoP

1月15日にいくつかの回答が追加されました。

回復後にすべてが成功した場合はどうすればよいですか?これらの質問についてはよくわかりません:

pg_create_physical_replication_slot( 'slot2');を実行して新しいスロット2を作成し、このスロットからpg_receivewal -D/media/extern/postgresql_archive -S slot2 -v?

これは選択かもしれません。要件に最適なテクノロジーを決定するのはあなた次第です。 pg_receivewalは使用していません。archive_commandを使用することをお勧めします。

pg_receivewal -D/media/extern/postgresql_archive -S slot1 -vを再実行しますか?

いいえ、できません!失われたレプリケーションは、pg_basebackupによるバックアップには含まれません。 basebackup中にserverlogを確認すると、次のように表示されます。

2019-01-14 16:32:02.886 CET sending backup "pg_basebackup base backup"     5c3cab72.27fc-12 4/0-0 [10236] DEBUG:  contents of directory "pg_replslot"   excluded from backup  

そのため、ホットバックアップからPGDATAを復元しても、レプリケーションスロットは復元されません。

別のベースバックアップを作成する必要があるのはいつですか?

それは本当にあなたの要件に依存します。目標復旧時間と目標復旧時点についての制約は何ですか?

1日でdbが切り替えるWalファイルの数は?

ドキュメントから:すべてのアーカイブされたWALファイルを最後のベースバックアップに戻す必要があるため、ベースバックアップの間隔は、アーカイブされたWALファイルに費やすストレージの量に基づいて選択する必要があります。リカバリが必要な場合は、リカバリに費やす準備ができている時間も考慮する必要があります。システムはこれらすべてのWALセグメントを再生する必要があり、最後のベースバックアップから長い時間が経過している場合は時間がかかる可能性があります。

いつ、なぜselect pg_switch_wal();を実行するのですか?)このリカバリコンセプトでは

このコマンドは、基本的にwalファイルを強制的に次のファイルに切り替えます。これにより、最後に完了したウォルマートがアーカイブdirに移動されます。ライブPGDATAが失われた(したがってpg_walサブディレクトリも)災害の場合、これは重要になる可能性があります。 Walファイルはデフォルトで16MBです。 archive_commandは、切り替えが発生したときにwalをアーカイブ先にコピーします。

災害が発生した場合、切り替え前の1バイトを例にとると、16MBのトランザクションアクティビティが失われます。これが、誰かがwalの完了を待たないpg_receivewalを好む理由です。ところで、archive_timeoutを使用して、要件と互換性のある値を設定できます。

1
MarcoP

recovery_target_time = '2018-01-06 16:22:00'

2018年ではなく、この2019年。サーバーログファイルを確認すると、回復が可能な限り早く(一貫した状態に達した直後に)停止したことがわかります。 、1年遅れています。

2
jjanes