PostgreSQL/解析

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の動作概要

pg_rewind_overview.png
pg_rewind_image_block_actions.png

ソースサーバ上のファイル一覧取得

ソースサーバのファイル一覧を知るために、ソースサーバ上で以下の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

参考

一度に転送される最大のデータサイズは、size 1000000となっている。ざっと1MB程度である。

ファイル転送の内部動作

  1. pg_rewindで転送するファイルに関する情報を一時テーブルでソースサーバ上に作成する。
    CREATE TEMPORARY TABLE fetchchunks(path text, begin int8, len int4);
  2. 続いて、COPYコマンドで、path、begin、lenの情報を各転送対象ソースに対して求める。
    COPY fetchchunks FROM STDIN;
  3. 最後は、SELECT分を発行し、実データを取得する。
    SELECT path, begin, pg_read_binary_file(path, begin, len, true) AS chunk FROM fetchchunks;

参考リンク


トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
目次
ダブルクリックで閉じるTOP | 閉じる
GO TO TOP