2012/12/09

pg_receivexlogで、リアルタイムにWALアーカイブ

この記事は、PostgreSQL Advent Calendar 2012の12/8担当分です。

今日は、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の書き込みとアーカイブは、以下のように行われます。

  1. 16MBいっぱいになるまで、pg_xlogディレクトリ内のWALファイルにWALを書き込み続ける
  2. WALファイルが16MBいっぱいになったら、archive_commandによりそのWALファイルをアーカイブする
  3. 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も起動/停止する必要があるなど、面倒な点がまだ多いです。しかし、故障時にデータが失われるのを回避できるため、トライしてみる価値はありそうです。