pg_rewind †タイムライン分岐したデータベースサーバを同期させるツール。例えば、レプリケーションでプライマリ、スタンバイとあって、プライマリが何らかの障害等で停止し、スタンバイがプライマリに昇格した時、スタンバイは新しいタイムラインでシステムを継続する。この後、プライマリを新しいスタンバイとして組み込みたい場合、pg_rewindコマンドを使用すると、新しいタイムラインのスタンバイ(新プライマリ)に同期させることができる。リカバリの方法としてpg_basebackupコマンドがあるが、こちらはデータベースディレクトリを丸々複製するのに対し、pg_rewindは差分データのみ同期させることで、データ転送量を抑えることができ、復旧時間の短縮化することができる。(更新内容にもよるが、データベースクラスタサイズが大きいシステムではpg_rewindがリカバリ時間の短縮をすることができるだろう)。 pg_rewind --debug -D primary/pgdata -P --source-server="host=localhost dbname=postgres port=5433" # source-serverとは、複製元となるサーバのことである。 # つまり新しく組み込もうとしているサーバを同期させるサーバである。 pg_rewindは、差分ファイル転送と巻き戻しを行うだけであり、コマンド実行以降は起動時リカバリ処理でソースサーバに追従する。復旧までに時間がかかり、ソースサーバ上のWALが既にアーカイブされて退避されていた場合、起動時リカバリ処理に失敗してしまうため、起動前にアーカイブWALをターゲットサーバに転送しておく必要がある。 例:ソースサーバ上のWALがアーカイブされてしまい、ターゲットサーバの起動時リカバリ処理で失敗してしまう LOCATION: libpqrcv_receive, libpqwalreceiver.c:757 LOG: 00000: started streaming WAL from primary at 0/4000000 on timeline 2 LOCATION: WalReceiverMain, walreceiver.c:409 FATAL: XX000: could not receive data from WAL stream: ERROR: requested WAL segment 000000020000000000000004 has already been removed pg_rewindの実行条件 †pg_rewindを実行するには、正常停止している必要がある。 pg_rewindの動作概要 †
ソースサーバ上のファイル一覧取得 †ソースサーバのファイル一覧を知るために、ソースサーバ上で以下のSQLが実行される。 WITH RECURSIVE files (path, filename, SIZE, isdir) AS ( SELECT '' AS path, filename, SIZE, isdir FROM (SELECT pg_ls_dir('.', TRUE, FALSE) AS filename) AS fn, pg_stat_file(fn.filename, TRUE) AS this UNION ALL\n" SELECT parent.path || parent.filename || '/' AS path, fn, this.size, this.isdir\n" FROM files AS parent,\n" pg_ls_dir(parent.path || parent.filename, true, false) AS fn, pg_stat_file(parent.path || parent.filename || '/' || fn, true) AS this WHERE parent.isdir = 't' ) SELECT path || filename, size, isdir, pg_tablespace_location(pg_tablespace.oid) AS link_target FROM files LEFT OUTER JOIN pg_tablespace ON files.path = 'pg_tblspc/' AND oid::text = files.filename; ただし、以下のリソースは対象外である。 # 対象外のディレクトリ pg_stat_tmp pg_replslot pg_dynshmem pg_notify pg_serial pg_snapshots pg_subtrans # 対象外のファイル postgresql.auto.conf.tmp current_logfiles.tmp backup_label tablespace_map postmaster.pid postmaster.opts デバッグ出力の例 †connected to server fetched file "global/pg_control", length 8192 fetched file "pg_wal/00000002.history", length 41 Source timeline history: Target timeline history: 1: 0/0 - 0/0 servers diverged at WAL location 0/301F968 on timeline 1 rewinding from last common checkpoint at 0/301F8F8 on timeline 1 reading source file list entry "postmaster.opts" excluded from source file list entry "postmaster.pid" excluded from source file list entry "global/pg_internal.init" excluded from source file list entry "pg_notify/0000" excluded from source file list entry "pg_subtrans/0000" excluded from source file list entry "base/12630/pg_internal.init" excluded from source file list reading target file list entry "pg_notify/0000" excluded from target file list entry "pg_subtrans/0000" excluded from target file list entry "postmaster.opts" excluded from target file list reading WAL in target backup_label.old (COPY) base/1/12465_fsm (COPY) base/1/12465_vm (COPY) base/1/12470_fsm (COPY) ... pg_stat/global.stat (REMOVE) need to copy 51 MB (total source directory size is 70 MB) getting file chunks received chunk for file "backup_label.old", offset 0, size 224 0/53164 kB (0%) copied received chunk for file "base/1/12465_fsm", offset 0, size 24576 received chunk for file "base/1/12465_vm", offset 0, size 8192 received chunk for file "base/1/12470_fsm", offset 0, size 24576 received chunk for file "base/1/12470_vm", offset 0, size 8192 ... received chunk for file "base/12630/16384", offset 50008192, size 1000000 ... received chunk for file "pg_wal/000000020000000000000003", offset 16000000, size 777216 received chunk for file "pg_xact/0000", offset 0, size 8192 received chunk for file "postgresql.auto.conf", offset 0, size 88 received chunk for file "postgresql.conf", offset 0, size 23809 received chunk for file "recovery.done", offset 0, size 274 received chunk for file "base/12630/16384", offset 8192, size 49152 53164/53164 kB (100%) copied creating backup label and updating control file syncing target data directory 転送されたテーブルのOIDからテーブル名を知りたい場合はoid2nameを使えば良い。 # contribモジュールにある $ cd contrib/oid2name $ make install # pgenv2を使っている場合 $ pgenv prefix --source "cd contrib/oid2name && make install" データベースpostgresのoidとテーブル名の対応を見る例は以下の通り。 $ oid2name -d postgres From database "postgres": Filenode Table Name ---------------------- 16384 t 参考 一度に転送される最大のデータサイズは、size 1000000となっている。ざっと1MB程度である。
ファイル転送の内部動作 †
pg_rewindの動作確認シェル †pg_rewindの動作を順を追って確認できるようなシェルを準備した。 pgenv2が必要である。 https://github.com/moritetu/pgenv2 bash rewind-study.sh
各ステップごとにプログラムを停止するようにしているので、状態確認しながら動作理解することができる。 ... # [Step-5] 2019年 1月12日 土曜日 22時57分33秒 JST # Down primary, go? [ENTER(yes)|n(no)|s(stop)]: waiting for server to shut down.... done server stopped # [Step-6] 2019年 1月12日 土曜日 22時57分37秒 JST # Promote standby, go? [ENTER(yes)|n(no)|s(stop)]: ... 参考リンク † |