今日は、PostgreSQL9.2の新機能pg_receivexlogを使って、リアルタイムにWALファイルをアーカイブする方法を検討してみたいと思います。
pg_receivexlogとは?
pg_receivexlogは、バージョン9.2からPostgreSQLに同梱されたコマンドです。このコマンドは、レプリケーションのスタンバイ側で、WALの受信と書き込みを繰り返すwalreceiverプロセスをツールとして切り出したものです。このコマンドにより、レプリケーションと同様に、リアルタイムにWALを任意の場所に転送し続けることができます。
pg_receivexlogの詳細は、pg_receivexlogの日本語ドキュメントとLet's PostgresのPostgreSQL9.2新機能紹介の記事を参考にしてください。
WALアーカイブの問題点
WALアーカイブには、ディスク故障時にデータが失われるかもしれないという問題点があります。以下、簡単に説明します。
まず、WALの書き込みとアーカイブは、以下のように行われます。
- 16MBいっぱいになるまで、pg_xlogディレクトリ内のWALファイルにWALを書き込み続ける
- WALファイルが16MBいっぱいになったら、archive_commandによりそのWALファイルをアーカイブする
- WALの書き込み先をpg_xlog内の次のWALファイルに切り替えて、1.に戻る
WALファイルがアーカイブされるのは、WALが16MB書き込まれるごとになります。このため、もしWALを16MB書き終わる直前に、ディスク故障などによりpg_xlogが破損すると、 バックアップから復旧できるのは前回アーカイブされたWALファイルまでになり、故障直前まで書き込んでいた16MB分のデータは完全に失われてしまいます。これがWALアーカイブの問題点です。
今回は、pg_receivexlogを使ってWALをリアルタイムにアーカイブ先に転送することで、このようなデータ損失が発生するのを回避します。
pg_receivexlogによるリアルタイムなWALアーカイブ
では、リアルタイムにWALアーカイブを行う環境を構築していきましょう。pg_receivexlogを使う必要があるため、当然環境構築にはPostgreSQL9.2を使います。まずは、通常どおりDBクラスタとWALアーカイブ先のディレクトリを作成します。
$ initdb -D data --encoding=UTF8 --locale=C
$ mkdir /mnt/archive
次に、WALアーカイブの設定を行います。
$ vi data/postgresql.conf
wal_level = archive
archive_mode = on
archive_command = 'pg_check_archive.sh /mnt/archive %f %p'
archive_commandに設定するスクリプトpg_check_archive.shを以下のとおり用意します。
$ vi my_archive_command.sh
#!/bin/sh
ARCHIVE=$1
WALFILE=$2
WALPATH=$3
case $WALFILE in
*.*)
cp $WALPATH $ARCHIVE/$WALFILE
;;
*)
sleep 5 && test -f $ARCHIVE/$WALFILE
;;
esac
$ chmod 744 my_archive_command.sh
このスクリプトの特徴は次のとおりです。
- このスクリプトには、第1引数にアーカイブ先のパスを、第2引数にWALファイル名(%f)を、第3引数にアーカイブするWALファイルのパス(%p)を指定する。
- WALファイルのアーカイブはpg_receivexlogが行うため、このスクリプトにアーカイブのためのコマンドを設定する必要はない。このスクリプトには、pg_receivexlogがWALファイルをアーカイブしたことを確認するコマンドを設定する。
- WALファイルのアーカイブを確認する前に、5秒間のスリープを追加する。archive_commandは、WALファイルが16MB書き終わるとすぐに実行される。一方、16MB書き終わってから、pg_receivexlogによるWAL転送が終わるまでの間には若干のタイムラグがある可能性がある。このタイムラグの間にアーカイブの完了確認が走らないように、5秒間スリープするようにする。
- pg_receivexlogは、WAL以外のファイル(バックアップ履歴ファイルやタイムライン履歴ファイル)を転送しない。このため、それらのファイルについては、このスクリプトがアーカイブを行うようにする。
次に、pg_receivexlogからのレプリケーション接続を受け付けられるように、マスタサーバとしての設定をpostgresql.confとpg_hba.confに行います。
$ vi data/postgresql.conf
max_wal_senders = 2
$ vi data/pg_hba.conf
local replication postgres trust
PostgreSQLとpg_receivexlogを起動します。なお、PostgreSQLを停止するときは、pg_receivexlogも忘れずに停止するようにしましょう。pg_receivexlogは、Ctrl-Cで停止できます。
$ pg_ctl -D data -w start
$ pg_receivexlog -D /mnt/archive
以降、WALは、pg_receivexlogによりリアルタイムに/mnt/archiveに転送されます。実際にWALを発生させて、どのようにWALがアーカイブされるのか確認してみましょう。WALの生成には、pgbenchの初期データ作成を使います。
$ pgbench -i -s5
$ ls data/pg_xlog
000000010000000000000001 000000010000000000000003 000000010000000000000005
000000010000000000000002 000000010000000000000004 archive_status
$ ls /mnt/archive
000000010000000000000001 000000010000000000000003 000000010000000000000005.partial
000000010000000000000002 000000010000000000000004
拡張子が.partialのWALファイルは、WALを書き込み途中(転送途中)であることを意味します。WALが16MBいっぱい書き込まれると、そのWALファイル名からは.partialは取り除かれ、次のWALファイルが.partialの拡張子で作成されます。
リカバリ
リアルタイムにWALをアーカイブする環境でも、バックアップからのリカバリ手順は基本的に通常のものと同じです。ただし、pg_xlogが破損した状況でバックアップからリカバリを行う場合(アーカイブのWALファイルのみでリカバリを行う場合)では、書き込み途中のWALファイルもリカバリ対象とするために、リカバリ開始前に.partialの拡張子をファイル名から取り除く必要があります。
まとめ
pg_receivexlogによるリアルタイムなWALアーカイブは、archive_command用の特別なスクリプトを用意する必要があったり、PostgreSQLの起動/停止と同時にpg_receivexlogも起動/停止する必要があるなど、面倒な点がまだ多いです。しかし、故障時にデータが失われるのを回避できるため、トライしてみる価値はありそうです。