PostgreSQL 13 PITR(Point In Time Recovery)タイムライン操作

スポンサーリンク

PostgreSQLのタイムラインIDを意識したPITR(Point In Time Recovery)の操作についてまとめます。PostgreSQLは、レプリケーション環境においてスタンバイからマスターへ昇格した時やPITRによる復旧を行なった時にタイムラインIDが1つ大きくなります。このタイムラインを意識した復旧操作についてまとめます。

検証シナリオ

以下のような操作シナリオを考えます。「太郎、次郎、三郎、四郎」の順にINSERTする事を想定していましたが、操作ミスをしてしまい、それを復旧させるシナリオを考えます。

PostgreSQL タイムライ3の操作

タイムライン1

誤って「太郎、次郎、四郎」の順にINSERTしてしまいました。

タイムライン2

本来「次郎」まで遡らなければならないところを誤って、「太郎」まで遡ってしまいました。操作ミスに気づかず、その後、「三郎、四郎」をINSERTしてしまいます。

タイムライン3

操作ミスに気付き、タイムライン1の「次郎」まで遡ります。その後、「三郎、四郎」をINSERTし、復旧に成功させます。

事前準備

アーカイビング

アーカイブの出力先としてNFSサーバを構築し、そこにWAL出力先用途のディレクトリを作成します。

NFSサーバの構築方法については説明を省略します。

mkdir -p /nfs/postgres/wal
chown -R postgres:postgres /nfs/postgres

postgresql.confを以下のように編集します。

# vi /var/lib/pgsql/13/data/postgresql.conf 

 <omitted>

archive_mode = on
archive_command = 'cp -p %p /nfs/postgres/wal/%f'
archive_timeout = 60

設定を反映させます。

systemctl restart postgresql-13.service

テストデータの投入

PostgreSQLのチュートリアル」から、DVDレンタルショップのサンプルデータベースをインポートします。

createdb dvdrental
wget https://sp.postgresqltutorial.com/wp-content/uploads/2019/05/dvdrental.zip
unzip dvdrental.zip
createdb dvdrental
pg_restore -d dvdrental dvdrental.tar

バックアップの取得

バックアップを取得します。

rm -rf /nfs/postgres/backup
pg_basebackup -D /nfs/postgres/backup -F t -X n -z

復旧操作例

タイムライン1

誤って「太郎、次郎、四郎」の順にINSERTしてしまいました。

PostgreSQL タイムライ1の操作

psql dvdrental << EOF
INSERT INTO actor (first_name, last_name) VALUES ('taro','yamada');
INSERT INTO actor (first_name, last_name) VALUES ('jiro','yamada');
INSERT INTO actor (first_name, last_name) VALUES ('shiro','yamada');
SELECT pg_switch_wal();
EOF

タイムライン2

本来「次郎」まで遡らなければならないところを誤って、「太郎」まで遡ってしまいました。操作ミスに気づかず、その後、「三郎、四郎」をINSERTしてしまいます。

PostgreSQL タイムライ2の操作

現在のLSNおよびWALファイルを確認します。

[postgres@centos10 ~]$ psql << EOF
> SELECT pg_walfile_name(pg_current_wal_lsn());
> SELECT pg_current_wal_lsn();
> EOF
     pg_walfile_name      
--------------------------
 000000010000000000000005
(1 row)

 pg_current_wal_lsn 
--------------------
 0/5000060
(1 row)

現在のWALが000000010000000000000005ですので、「太郎、次郎、四郎」がINSERTされたのは1つ前のWALである000000010000000000000004です。これをpg_waldumpコマンドで閲覧すると、「太郎、次郎、四郎」に対応した3回のCOMMIT操作があるのが読み取れます。

以下ログの場合は「太郎」のCOMMITである「lsn : 0/04002CD8」までの遡りを試みます。

[postgres@centos10 ~]$ /usr/pgsql-13/bin/pg_waldump /nfs/postgres/wal/000000010000000000000004 
rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 0/04000028, prev 0/03000100, desc: RUNNING_XACTS nextXid 676 latestCompletedXid 675 oldestRunningXid 676
rmgr: Sequence    len (rec/tot):     99/    99, tx:        676, lsn: 0/04000060, prev 0/04000028, desc: LOG rel 1663/16384/16419, blkref #0: rel 1663/16384/16419 blk 0
rmgr: Heap        len (rec/tot):     54/  3410, tx:        676, lsn: 0/040000C8, prev 0/04000060, desc: INSERT off 59 flags 0x00, blkref #0: rel 1663/16384/16421 blk 1 FPW
rmgr: Btree       len (rec/tot):     53/  4113, tx:        676, lsn: 0/04000E20, prev 0/040000C8, desc: INSERT_LEAF off 201, blkref #0: rel 1663/16384/16556 blk 1 FPW
rmgr: Btree       len (rec/tot):     53/  3773, tx:        676, lsn: 0/04001E38, prev 0/04000E20, desc: INSERT_LEAF off 122, blkref #0: rel 1663/16384/16587 blk 1 FPW
rmgr: Transaction len (rec/tot):     34/    34, tx:        676, lsn: 0/04002D10, prev 0/04001E38, desc: COMMIT 2020-12-24 21:54:55.566531 JST
rmgr: Standby     len (rec/tot):     54/    54, tx:          0, lsn: 0/04002D38, prev 0/04002D10, desc: RUNNING_XACTS nextXid 677 latestCompletedXid 675 oldestRunningXid 676; 1 xacts: 676
rmgr: Heap        len (rec/tot):     79/    79, tx:        677, lsn: 0/04002D70, prev 0/04002D38, desc: INSERT off 60 flags 0x00, blkref #0: rel 1663/16384/16421 blk 1
rmgr: Btree       len (rec/tot):     64/    64, tx:        677, lsn: 0/04002DC0, prev 0/04002D70, desc: INSERT_LEAF off 202, blkref #0: rel 1663/16384/16556 blk 1
rmgr: Btree       len (rec/tot):     64/    64, tx:        677, lsn: 0/04002E00, prev 0/04002DC0, desc: INSERT_LEAF off 123, blkref #0: rel 1663/16384/16587 blk 1
rmgr: Transaction len (rec/tot):     34/    34, tx:        677, lsn: 0/04002E40, prev 0/04002E00, desc: COMMIT 2020-12-24 21:54:55.569405 JST
rmgr: Heap        len (rec/tot):     87/    87, tx:        678, lsn: 0/04002E68, prev 0/04002E40, desc: INSERT off 61 flags 0x00, blkref #0: rel 1663/16384/16421 blk 1
rmgr: Btree       len (rec/tot):     64/    64, tx:        678, lsn: 0/04002EC0, prev 0/04002E68, desc: INSERT_LEAF off 203, blkref #0: rel 1663/16384/16556 blk 1
rmgr: Btree       len (rec/tot):     64/    64, tx:        678, lsn: 0/04002F00, prev 0/04002EC0, desc: INSERT_LEAF off 124, blkref #0: rel 1663/16384/16587 blk 1
rmgr: Transaction len (rec/tot):     34/    34, tx:        678, lsn: 0/04002F40, prev 0/04002F00, desc: COMMIT 2020-12-24 21:54:55.570508 JST
rmgr: XLOG        len (rec/tot):     24/    24, tx:          0, lsn: 0/04002F68, prev 0/04002F40, desc: SWITCH

PostgreSQLの復旧データを所定のディレクトリに配置します。

systemctl stop postgresql-13.service 
rm -rf /var/lib/pgsql/13/data/*
touch /var/lib/pgsql/13/data/recovery.signal
cd /var/lib/pgsql/13/data/
tar xvzf /nfs/postgres/backup/base.tar.gz

リストアに関するパラメタをpostgresql.confに加筆します。後述の検証シナリオの都合上、アーカイビングに関するパラメタは変更せず、そのままとして下さい。

# vi postgresql.conf

archive_mode = on
archive_command = 'cp -p %p /nfs/postgres/wal/%f'
archive_timeout = 60
restore_command = 'cp /nfs/postgres/wal/%f %p'
recovery_target_action = 'promote'
recovery_target_lsn = '0/04002D10'
archive_cleanup_command = '/usr/pgsql-13/bin/pg_archivecleanup /nfs/postgres/wal/ %r'

PostgreSQLを復旧させ、PITRを実行します。

systemctl start postgresql-13.service

「三郎、四郎」をINSERTします。

psql dvdrental << EOF
INSERT INTO actor (first_name, last_name) VALUES ('saburo','yamada');
INSERT INTO actor (first_name, last_name) VALUES ('shiro','yamada');
SELECT pg_switch_wal();
EOF

WALのファイル名を確認します。00000001で始まるファイルと00000002で始まるファイルがあります。この数字がタイムラインIDです。

[postgres@centos10 ~]$ ls -l /nfs/postgres/wal/
total 114696
-rw-------. 1 postgres postgres 16777216 Dec 24 21:51 000000010000000000000001
-rw-------. 1 postgres postgres 16777216 Dec 24 21:52 000000010000000000000002
-rw-------. 1 postgres postgres 16777216 Dec 24 21:54 000000010000000000000003
-rw-------. 1 postgres postgres      337 Dec 24 21:54 000000010000000000000003.00000028.backup
-rw-------. 1 postgres postgres 16777216 Dec 24 21:54 000000010000000000000004
-rw-------. 1 postgres postgres 16777216 Dec 24 21:56 000000010000000000000005
-rw-------. 1 postgres postgres 16777216 Dec 24 22:04 000000020000000000000004
-rw-------. 1 postgres postgres 16777216 Dec 24 22:08 000000020000000000000005
-rw-------. 1 postgres postgres       33 Dec 24 22:02 00000002.history
[postgres@centos10 ~]$ 

WALの格納先を見ると、.historyというファイルがあります。これがどのようにタイムラインが遷移したかを記録するファイルです。例えば以下のような出力ならば、タイムライン1のLSN 0/4002D10の後にタイムライン2に遷移した事が分かります。

[postgres@centos10 ~]$ cat /nfs/postgres/wal/00000002.history
1 0/4002D38 after LSN 0/4002D10

[postgres@centos10 ~]$ 

actorテーブルを確認します。すると、「次郎」のINSERTを忘れている事に気づきます。

[postgres@centos10 ~]$ psql dvdrental -c "SELECT * FROM actor"


      200 | Thora       | Temple       | 2013-05-26 14:47:57.62
      201 | taro        | yamada       | 2020-12-24 21:54:55.565001
      234 | saburo      | yamada       | 2020-12-24 22:04:21.666698
      235 | shiro       | yamada       | 2020-12-24 22:04:21.672565
(203 rows)

タイムライン2

操作ミスに気付き、タイムライン1の「次郎」まで遡ります。その後、「三郎、四郎」をINSERTし、復旧に成功させます。

PostgreSQL タイムライ3の操作

タイムラインWALファイルの中身をもう一度確認します。タイムライン1の「次郎」に相当するLSNは「lsn: 0/04002E40」である事が分かります。

[postgres@centos10 ~]$ /usr/pgsql-13/bin/pg_waldump /nfs/postgres/wal/000000010000000000000004 
rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 0/04000028, prev 0/03000100, desc: RUNNING_XACTS nextXid 676 latestCompletedXid 675 oldestRunningXid 676
rmgr: Sequence    len (rec/tot):     99/    99, tx:        676, lsn: 0/04000060, prev 0/04000028, desc: LOG rel 1663/16384/16419, blkref #0: rel 1663/16384/16419 blk 0
rmgr: Heap        len (rec/tot):     54/  3410, tx:        676, lsn: 0/040000C8, prev 0/04000060, desc: INSERT off 59 flags 0x00, blkref #0: rel 1663/16384/16421 blk 1 FPW
rmgr: Btree       len (rec/tot):     53/  4113, tx:        676, lsn: 0/04000E20, prev 0/040000C8, desc: INSERT_LEAF off 201, blkref #0: rel 1663/16384/16556 blk 1 FPW
rmgr: Btree       len (rec/tot):     53/  3773, tx:        676, lsn: 0/04001E38, prev 0/04000E20, desc: INSERT_LEAF off 122, blkref #0: rel 1663/16384/16587 blk 1 FPW
rmgr: Transaction len (rec/tot):     34/    34, tx:        676, lsn: 0/04002D10, prev 0/04001E38, desc: COMMIT 2020-12-24 21:54:55.566531 JST
rmgr: Standby     len (rec/tot):     54/    54, tx:          0, lsn: 0/04002D38, prev 0/04002D10, desc: RUNNING_XACTS nextXid 677 latestCompletedXid 675 oldestRunningXid 676; 1 xacts: 676
rmgr: Heap        len (rec/tot):     79/    79, tx:        677, lsn: 0/04002D70, prev 0/04002D38, desc: INSERT off 60 flags 0x00, blkref #0: rel 1663/16384/16421 blk 1
rmgr: Btree       len (rec/tot):     64/    64, tx:        677, lsn: 0/04002DC0, prev 0/04002D70, desc: INSERT_LEAF off 202, blkref #0: rel 1663/16384/16556 blk 1
rmgr: Btree       len (rec/tot):     64/    64, tx:        677, lsn: 0/04002E00, prev 0/04002DC0, desc: INSERT_LEAF off 123, blkref #0: rel 1663/16384/16587 blk 1
rmgr: Transaction len (rec/tot):     34/    34, tx:        677, lsn: 0/04002E40, prev 0/04002E00, desc: COMMIT 2020-12-24 21:54:55.569405 JST
rmgr: Heap        len (rec/tot):     87/    87, tx:        678, lsn: 0/04002E68, prev 0/04002E40, desc: INSERT off 61 flags 0x00, blkref #0: rel 1663/16384/16421 blk 1
rmgr: Btree       len (rec/tot):     64/    64, tx:        678, lsn: 0/04002EC0, prev 0/04002E68, desc: INSERT_LEAF off 203, blkref #0: rel 1663/16384/16556 blk 1
rmgr: Btree       len (rec/tot):     64/    64, tx:        678, lsn: 0/04002F00, prev 0/04002EC0, desc: INSERT_LEAF off 124, blkref #0: rel 1663/16384/16587 blk 1
rmgr: Transaction len (rec/tot):     34/    34, tx:        678, lsn: 0/04002F40, prev 0/04002F00, desc: COMMIT 2020-12-24 21:54:55.570508 JST
rmgr: XLOG        len (rec/tot):     24/    24, tx:          0, lsn: 0/04002F68, prev 0/04002F40, desc: SWITCH

PostgreSQLの復旧データを所定のディレクトリに配置します。

systemctl stop postgresql-13.service 
rm -rf /var/lib/pgsql/13/data/*
touch /var/lib/pgsql/13/data/recovery.signal
cd /var/lib/pgsql/13/data/
tar xvzf /nfs/postgres/backup/base.tar.gz

リストアに関するパラメタをpostgresql.confに加筆します。後述の検証シナリオの都合上、アーカイビングに関するパラメタは変更せず、そのままとして下さい。

注意すべきはrecovery_target_timelineというパラメタです。デフォルト設定の場合は最新のタイムラインのWALを適用しますが、最新のWALを適用したくない場合はrecovery_target_timelineを明示指定する必要があります。

# vi postgresql.conf

archive_mode = on
archive_command = 'cp -p %p /nfs/postgres/wal/%f'
archive_timeout = 60
restore_command = 'cp /nfs/postgres/wal/%f %p'
recovery_target_action = 'promote'
recovery_target_lsn = '0/04002E40'
archive_cleanup_command = '/usr/pgsql-13/bin/pg_archivecleanup /nfs/postgres/wal/ %r'
recovery_target_timeline = '1'

PostgreSQLを復旧させ、PITRを実行します。

systemctl start postgresql-13.service

「三郎、四郎」をINSERTします。

psql dvdrental << EOF
INSERT INTO actor (first_name, last_name) VALUES ('saburo','yamada');
INSERT INTO actor (first_name, last_name) VALUES ('shiro','yamada');
SELECT pg_switch_wal();
EOF

WALのファイル名を確認します。タイムライン1から3までのファイルがある事が分かります。

[root@centos10 data]# ls -l /nfs/postgres/wal/
合計 131084
-rw-------. 1 postgres postgres 16777216 12月 24 21:51 000000010000000000000001
-rw-------. 1 postgres postgres 16777216 12月 24 21:52 000000010000000000000002
-rw-------. 1 postgres postgres 16777216 12月 24 21:54 000000010000000000000003
-rw-------. 1 postgres postgres      337 12月 24 21:54 000000010000000000000003.00000028.backup
-rw-------. 1 postgres postgres 16777216 12月 24 21:54 000000010000000000000004
-rw-------. 1 postgres postgres 16777216 12月 24 21:56 000000010000000000000005
-rw-------. 1 postgres postgres       33 12月 24 22:02 00000002.history
-rw-------. 1 postgres postgres 16777216 12月 24 22:04 000000020000000000000004
-rw-------. 1 postgres postgres 16777216 12月 24 22:08 000000020000000000000005
-rw-------. 1 postgres postgres       33 12月 24 22:21 00000003.history
-rw-------. 1 postgres postgres 16777216 12月 24 22:24 000000030000000000000004
[root@centos10 data]# 

WALの格納先を見ると、.historyというファイルがあります。これがどのようにタイムラインが遷移したかを記録するファイルです。例えば以下のような出力ならば、タイムライン1のLSN 0/4002E40の後にタイムライン3に遷移した事が分かります。

[root@centos10 data]# cat /nfs/postgres/wal/00000003.history
1 0/4002E68 after LSN 0/4002E40

[root@centos10 data]# 

actorテーブルを確認します。「太郎、次郎、三郎、四郎」の順にINSERTできている事が分かります。

[postgres@centos10 ~]$ psql dvdrental -c "SELECT * FROM actor"


      200 | Thora       | Temple       | 2013-05-26 14:47:57.62
      201 | taro        | yamada       | 2020-12-24 21:54:55.565001
      202 | jiro        | yamada       | 2020-12-24 21:54:55.568998
      234 | saburo      | yamada       | 2020-12-24 22:24:40.04214
      235 | shiro       | yamada       | 2020-12-24 22:24:40.044846
(204 rows)
タイトルとURLをコピーしました