|
この情報はすでに古くなっています。 1024倍以上グレードアップした内部構造は、 毎度おなじみ、流浪のPostgreSQL本にまとめました(今回の書名は「PostgreSQL全機能バイブル」)。 書籍以外のPostgreSQL情報はこちらを参照してください。 pgpool-IIによるレプリケーションとオンラインリカバリこの記事は技術評論社『WEB+DB PRESS』の 『WEB+DB PRESS Vol.48』2008年12月刊 に掲載された原稿の草稿を、許可を得て公開しているものです。また、日本PostgreSQLユーザ会の仕組み分科会で発表したWALとPITRの資料とpgpool-IIのオンラインリカバリに関する資料がありますので、こちらも参照してください。 1.1 はじめに本章では、pgpool-IIによるレプリケーションシステムの構成方法と、 オンラインリカバリの手順について解説します。1.2 pgpool-IIとはpgpool-IIは同期レプリケーション機能をはじめ、コネクションプール機能や負荷分散機能を提供するPostgreSQL専用のミドルウエアです。pgpool-IIは、先代に当たるpgpoolの後継プロダクトとしてリリースされました。pgpool-IIの概略を把握するために、pgpoolからの開発の歴史を簡単に振り返ってみましょう(表1)。
そもそもpgpoolは、PostgreSQLのコネクションプールサーバとして誕生しました。
PostgreSQLやOracleなどのRDBMSは、アプリケーションから接続を要求される毎にプロセスを起動してSQL文を実行します(図1)。
また、 PostgreSQLの前段で機能するというpgpoolの特徴から、 非常に早い段階に同期レプリケーションも実装されました(図3)。 これは、各pgpoolプロセスが2台のPostgreSQLサーバに接続し、 (1)アプリケーションから受け取った更新系のSQLを、(2)2台のPostgreSQLに転送するというものでした。
バージョン1のリリース以降、pgpoolは性能向上やバグフィックスが続けられましたが、 レプリケーションは2台までという制約がありました。
2006年9月、pgoolの後継としてpgpool-IIのバージョン1.0がリリースされました。
ここでレプリケーションの台数制限が撤廃され、3台以上の構成が可能となりました。
さらに2007年11月にpgpool-IIのバージョン2がリリースされ、オンラインリカバリ機能が実装されました。
1.3 システム構成とインストール環境以降、3台のサーバを使ってpgpool-IIのレプリケーション機能、およびオンラインリカバリ機能について説明します。 今回のシステム構成に(図4)に示します。適宜、自身の環境に合わせて読みかえてください。
全サーバに"postgres"というユーザを登録してください。インストール作業はユーザpostgresで行います。
export PATH=$PATH:/usr/local/pgsql/bin:/usr/local/pgpool2/bin 全サーバにrsyncとsshがインストール済みと仮定します。 また、サーバpgpoolはポート番号9999と9898に接続可能、 サーバpostgres0とpostgres1はポート番号5432に接続可能となるように、OSの設定を行ってください。 なお、以降の説明における、ターミナルで作業する場合のプロンプト表示は次の形式とします。 ユーザ名 @ サーバ名> 例えば、ユーザpostgresがサーバpostgres0で作業する場合は postgres@postgres0>とします。 特に、2台のPostgreSQLサーバpostgres0とpostgres1で共通の作業を行う場合は postgres@>と表記します。 1.4 PostgreSQLのインストールはじめにPostgreSQLをインストールします。 pgpool-IIもPostgreSQLのライブラリlibpqを利用するので、 すべてのサーバにPostgreSQLをインストールすることにします。1.4.1 ソフトウエアの入手PostgreSQLを入手します。最新版は8.3.4です。http://www.postgresql.org/ftp/source/v8.3.4/
1.4.2 インストールPostgreSQLの最新版をダウンロードしたら、適当なディレクトリで展開し、 configureコマンドとmakeコマンドを実行します。root@> mkdir /usr/local/pgsql root@> chown postgres:postgres /usr/local/pgsql root@> su postgres postgres@> tar xvfz postgresql-8.3.4.tar.gz postgres@> cd postgresql-8.3.4 postgres@> ./configure postgres@> make && make install デフォルトのインストールディレクトリは/usr/local/pgsql/です。 1.4.3 設定インストールが終了したら、PostgreSQLを稼働させる2台のサーバ:postgres0とpostgres1で以下の設定を行います。1.4.3.1 データベースの初期化データベースの初期化を行います。以下のコマンドを実行してください。postgres@> initdb -D /usr/local/pgsql/data これでディレクトリ/usr/local/pgsql/data以下にデータベースが作成されます。 このディレクトリを「ベースディレクトリ」、ベースディレクトリ以下のデータを「データベースクラスタ」とよびます。 1.4.3.2 アーカイブログディレクトリの作成アーカイブログを保存するディレクトリを作成します。 ここでは、ベースディレクトリにarchive_logというディレクトリを作成します。postgres@> mkdir /usr/local/pgsql/data/archive_log 1.4.3.3 設定ファイル以上の準備が終わったら、2つの設定ファイルpostgresql.confとpg_hba.confの編集を行います。 これらはベースディレクトリ(今回はディレクトリ"/usr/local/pgsql/data")にあります。1つ目のファイルはposgtresql.confです(リスト1)。 数多くのパラメータがありますが、今回は次の3つのパラメータを設定してください。
listen_addresses = '*' archive_mode = on archive_command = 'cp %p /usr/local/pgsql/data/archive_log/%f' パラメータlisten_addressesはpgpool-IIからのアクセスを許可するために必要です。 行頭の"#"を消去して、設定値を"'*'"としてください。 パラメータarchive_modeとarchive_commandはオンラインリカバリのために必要です。 同じく行頭の"#"を消去して、それぞれ値を設定してください。 パラメータarchive_commandの設定値にあるディレクトリ"/usr/local/pgsql/data/archive_log/"は 上で作成したアーカイブログの保存ディレクトリを記述してください。
2つ目のファイルはアクセス制御ファイルpg_hba.confです。
ここでは、ネットワーク192.168.1.0からのアクセスはすべて許可する設定をします。
(リスト2)に示した行をpg_hba.confファイルの末尾に追加してください。
host all all 192.168.1.0/24 trust
1.4.4 PostgreSQLサーバの起動以上でPostgreSQLの準備が整ったので、PostgreSQLを起動しましょう。 以下のコマンドを実行してください。postgres@> pg_ctl -D /usr/local/pgsql/data start 次に、これから実験で使うデータベースsampledbを作成しましょう。 createdbコマンドでデータベースを作成します。 postgres@> createdb sampledb 1.5 pgpool-IIのインストールPostgreSQLの準備が終わったら、今度はサーバpgpool上でpgpool-IIのインストールを行います。
1.5.1 ソフトウエアの入手pgpool-IIの最新版を入手します。最新版は2.1です。http://pgfoundry.org/projects/pgpool/ http://pgfoundry.org/frs/download.php/1843/pgpool-II-2.1.tar.gz 1.5.2 インストールpgpool-IIの最新版をダウンロードしたら、 適当なディレクトリで展開し、configureコマンドとmakeコマンドを実行します。 configureコマンドの"--with-pgsql-libdir"オプションにはライブラリlibpq.soのあるディレクトリを指定します。root@pgpool> mkdir /usr/local/pgpool2 root@pgpool> chown postgres:postgres /usr/local/pgpool2 root@pgpool> su postgres postgres@pgpool> tar xvfz pgpool-II-2.1.tar.gz postgres@pgpool> cd pgpool-II-2.1 postgres@pgpool> ./configure --prefix=/usr/local/pgpool2 \ > --with-pgsql-libdir=/usr/local/pgsql/lib postgres@pgpool> make && make install postgres@pgpool> cd sql/pgpool-recovery postgres@pgpool> make && make install インストールディレクトリは/usr/local/pgpool2/です。このディレクトリ以下に各種ファイルがインストールされます。 1.5.3 設定pgpool-IIのインストールが終了したら、3つの設定ファイルを準備します。 それぞれサンプルファイルが用意されているので、予めこれらをコピーしておきましょう。postgres@pgpool> cd /usr/local/pgpool2/etc postgres@pgpool> cp pcp.conf.sample pcp.conf postgres@pgpool> cp pgpool.conf.sample pgpool.conf postgres@pgpool> cp pool_hba.conf.sample pool_hba.conf 1.5.3.1 pcp.confpcp.confファイルは、pgpool-IIを制御するpcp関連コマンドの認証のために必要になります。 ここではユーザ名"pgpool2"、パスワードも"pgpool2"として登録します。 (リスト3)に示した行をpcp.confファイルの末尾に追加してください。
pgpool2:027adbeda60c4110f38c4d484c6f9731 pcp.confファイルの書式は「ユーザ名:パスワードのmd5ハッシュ値」で、md5ハッシュ値はコマンドpg_md5で得ることができます。 postgres@pgpool> pg_md5 pgpool2 027adbeda60c4110f38c4d484c6f9731 1.5.3.2 pgpool.conf次に、pgpoolの基本動作を制御するための設定ファイルpgpool.confを編集します。レプリケーションモードで動作させるために(リスト4)で示す項目を設定してください。
1: # pgpool-IIへのアクセスを許可するネットワークやアドレスを指定する 2: listen_addresses = '*' # '*'を設定すると、無条件で接続可能 3: port = 9999 # pgpool-IIのアクセスポート 4: pcp_port = 9898 # pgpool-IIの制御用アクセスポート 5: 6: # pgpool-IIをレプリケーションモードで起動 7: replication_mode = true 8: 9: # ノード0 => サーバpostgres0の情報を設定 10: backend_hostname0 = '192.168.1.100' # サーバpostgres0のIPアドレス 11: backend_port0 = 5432 # PostgreSQLのポート番号 12: backend_weight0 = 1 13: backend_data_directory0 = '/usr/local/pgsql/data' # ベースディレクトリ 14: 15: # ノード1 => サーバpostgres1の情報を設定 16: backend_hostname1 = '192.168.1.101 # サーバpostgres1のIPアドレス 17: backend_port1 = 5432 # PostgreSQLのポート番号 18: backend_weight1 = 1 19: backend_data_directory1 = '/usr/local/pgsql/data' # ベースディレクトリ pgpool-IIは各PostgreSQLサーバを"ノード"として管理して、 例えば"backend_hostname0"や"backend_port0"など末尾が0の場合は"ノード0"となります。 今回の場合はサーバpostgres0がノード0、サーバpostgres1がノード1となります。
1.5.3.3 pool_hba.conf最後に、pgpool-IIのアクセス制御を行う設定ファイルpool_hba.confを編集します。 書式はPostgreSQLのアクセス制御ファイルpg_hba.confと同じです。ここでは説明の簡略化のため、セキュリティを無視して(リスト5)の行を追加してください。
host all all 127.0.0.1/32 trust host all all 192.168.1.0/24 trust これにより、ネットワーク192.168.1.0からのアクセスはすべて許可されます。
1.5.4 PostgreSQLでの設定pgpool-IIの設定が終わったら、最後の仕上げです。 オンラインリカバリのためのライブラリをPostgreSQLサーバにコピーし、 バッチファイルを実行します。まず、ライブラリpgpool-recovery.soをPostgreSQLのあるサーバの/usr/local/pgsql/libに、 バッチファイルpgpool-recovery.sqlを/usr/local/pgsql/shareにコピーします(図5)。
postgres@pgpool> cd sql/pgpool-recovery postgres@pgpool> scp pgpool-recovery.so 192.168.1.100:/usr/local/pgsql/lib postgres@pgpool> scp pgpool-recovery.so 192.168.1.101:/usr/local/pgsql/lib postgres@pgpool> scp pgpool-recovery.sql 192.168.1.100:/usr/local/pgsql/share postgres@pgpool> scp pgpool-recovery.sql 192.168.1.101:/usr/local/pgsql/share つぎに、各PostgreSQLサーバ上でバッチファイルpgpool-recovery.sqlを実行します(図6)。
postgres@> psql -c "\i /usr/local/pgsql/contrib/pgpool-recovery.sql" -U postgres template1 1.6 動作確認すべての準備が終わったので、システムの動作確認を行いましょう。まず、pgpool-IIを起動します。pgpoolコマンドを引数なしで実行してください。 postgres@pgpool> pgpool 無事起動したら、pgpool-IIに接続してみましょう(図7)。 PostgreSQLのターミナルソフトpsqlで接続しますが、 "-h"オプションにpgpool-IIが起動しているサーバのIPアドレス192.168.1.200、 "-p"オプションに9999を設定してください。 接続できたら、テスト用のテーブルtblを作成し、いくつかデータを挿入してみます。
postgres@pgpool> psql -h 192.168.1.200 -p 9999 sampledb -q sampledb=# CREATE TABLE tbl(id int); CREATE TABLE sampledb=# INSERT INTO tbl VALUES (1); INSERT 0 1 sampledb=# INSERT INTO tbl VALUES (2); INSERT 0 1 sampledb=# INSERT INTO tbl VALUES (3); INSERT 0 1 sampledb=# SELECT * FROM tbl; id ---- 1 2 3 (3 rows) うまくpgpool-IIが動作したのか、直接PostgreSQLサーバに接続して確認してみましょう(図8)。 サーバpostgres0のIPアドレス192.168.1.100を"-h"オプションに設定して接続します。 実際にサーバpostgres0にテーブルtblが作成されていたことが確認できたでしょうか。
postgres@pgpool> psql -h 192.168.1.100 sampledb -q sampledb=# SELECT * FROM tbl; id ---- 1 2 3 (3 rows) pgpool-IIを停止する場合は、stopオプションをつけてpgpoolコマンドを実行します。 postgres@pgpool> pgpool stop 1.7 オンラインリカバリここまでpgpool-IIによるレプリケーションについて説明してきました。 これからいよいよ高可用性の要、オンラインリカバリについて説明します。
1.7.1 オンラインリカバリの仕組みpgpool-IIのオンラインリカバリの仕組みを解説します(図9)。pgpool-IIのオンラインリカバリは、2つのフェーズにわかれています。
フェーズ1ではデータ操作が可能です。 フェーズ1の期間に更新されたデータはフェーズ2で転送されて、リカバリするサーバに反映されます。 よって、フェーズ2の期間はデータ操作を禁止しなければなりません。 pgpool-IIはすべての接続が切断されるまでフェーズ2に入らずに待機します。
厳密に言えばフェーズ2の間はデータベースアクセスができないので、
「システム停止なしでリカバリできる」とはいえないかもしれませんが、
フェーズ2にかかる時間はフェーズ1で更新されたデータが反映されているアーカイブログの転送と、
PostgreSQLサーバの起動にかかる時間だけですので、
早ければ数秒で終了します。
1.8 オンラインリカバリの準備1.8.1 SSHPostgreSQLをインストールした2台のサーバ間でパスワード入力なしでsshコマンドを実行するため(脚注1)、 サーバpostgres0で(図10)、 サーバpostgres1で(図11)の作業を行います。
postgres@postgres0> ssh-keygen -t dsa # パスフレーズは空白 postgres@postgres0> scp ~/.ssh/id_dsa.pub 192.168.1.101:~/ postgres@postgres0> ssh 192.168.1.101 postgres@postgres1> cat id_dsa.pub >> ~/.ssh/authorized_keys2 postgres@postgres1> rm id_dsa.pub
postgres@postgres1> ssh-keygen -t dsa # パスフレーズは空白 postgres@postgres1> scp ~/.ssh/id_dsa.pub 192.168.1.100:~/ postgres@postgres1> ssh 192.168.1.100 postgres@postgres0> cat id_dsa.pub >> ~/.ssh/authorized_keys2 postgres@postgres0> rm id_dsa.pub 念のため,ファイルとディレクトリのパーミッションを再設定してください。 postgres@postgres0> chmod 700 ~/.ssh postgres@postgres0> chmod 600 ~/.ssh/authorized_keys2 postgres@postgres1> chmod 700 ~/.ssh postgres@postgres1> chmod 600 ~/.ssh/authorized_keys2 1.8.2 スクリプトサーバpostgres0とpostgres1のベースディレクトリ(ここでは/usr/local/pgsql/data)に、 シェルスクリプトrecovery_1st_stage.sh(図12)とrecovery_2nd_stage.sh(図13)とpgpool_remote_start(図14)を置き、パーミッションを実行可能としてください。postgres@> cd /usr/local/pgsql/data postgres@> chmod +x recovery_1st_stage.sh postgres@> chmod +x recovery_2nd_stage.sh postgres@> chmod +x pgpool_remote_start
#! /bin/bash PSQL=/usr/local/pgsql/bin/psql MASTER_BASEDIR=$1 RECOVERY_HOST=$2 RECOVERY_BASEDIR=$3 # ベースバックアップの開始 $PSQL -c "SELECT pg_start_backup('pgpool-recovery')" postgres # リカバリ先用のrecovry.confファイル生成 echo "restore_command = 'cp $RECOVERY_BASEDIR/archive_log/%f %p'" > $MASTER_BASEDIR/recovery.conf # リカバリ先のデータベースクラスタを念のためにバックアップ ssh -T $RECOVERY_HOST rm -rf $RECOVERY_BASEDIR.bk ssh -T $RECOVERY_HOST mv -f $RECOVERY_BASEDIR{,.bk} # データベースクラスタ=ベースバックアップをリカバリ先に転送 rsync -az -e ssh $MASTER_BASEDIR/ $RECOVERY_HOST:$RECOVERY_BASEDIR/ ssh -T $RECOVERY_HOST cp -f $RECOVERY_BASEDIR.bk/postgresql.conf $RECOVERY_BASEDIR ssh -T $RECOVERY_HOST rm -f $RECOVERY_BASEDIR/postmaster.pid # リカバリ先に転送したので、不要になったrecovery.confを削除 rm -f $MASTER_BASEDIR/recovery.conf # ベースバックアップの終了 $PSQL -c "SELECT pg_stop_backup()" postgres
#! /bin/bash PSQL=/usr/local/pgsql/bin/psql MASTER_BASEDIR=$1 RECOVERY_HOST=$2 RECOVERY_BASEDIR=$3 # 最新のアーカイブログを保存 $PSQL -c 'SELECT pg_switch_xlog()' postgres # 最新のアーカイブログをリカバリ先に転送 rsync -az -e ssh $MASTER_BASEDIR/archive_log/ $RECOVERY_HOST:$RECOVERY_BASEDIR/archive_log/
#! /bin/sh PGCTL=/usr/local/pgsql/bin/pg_ctl RECOVERY_HOST=$1 RECOVERY_BASEDIR=$2 # リカバリ先のPostgreSQLを起動 ssh -T $RECOVERY_HOST $PGCTL -w -D $RECOVERY_BASEDIR start 2>/dev/null 1> /dev/null < /dev/null & これらのスクリプトがどのような働きをするか、(図15)に時系列で示します。
ここでは、サーバpostgres0からサーバpostgres1(リカバリ先)をリカバリするとします。
次セクションで説明するpcp_recovery_nodeコマンドをpgpool-IIが受け取ると、
オンラインリカバリが始まります。
フェーズ1では、pgpool-IIはサーバpostgres0にpgpool_recovery()関数を実行させます。
ここでpgpool_recovery()関数は、pgpool-IIインストール時に設定したライブラリpgpool-recovery.soと
バッチファイルpgpool-recovery.sqlによってPostgreSQLに登録された関数で、
ベースディレクトリにあるシェルスクリプトを実行します。
ここではrecvery_1st_stage.shを実行します。
フェーズ1が終わると、全接続が切断されるのを待ってフェーズ2に入ります。
フェーズ2では、recovery_2nd_stage.shが実行されます。
recovery_2nd_stage.sh(図13)では、サーバpostgres0でpg_switch_xlog()関数を実行して
最新のアーカイブログを書き出し、そのアーカイブログをrsyncのsshモードで転送しています。
1.9 オンラインリカバリの実行以上でオンラインリカバリを試す準備が整いました。これから、pgpool-IIの制御を行う6つのコマンドを説明しながら、 オンラインリカバリを行います。 ここで説明するコマンドの主役は、先に(図15)で登場したpcp_recevory_nodeですが、 他のコマンドもpgpool-IIを運用するために必須です。 1.9.1 pcp_node_countはじめに、pcp_node_countコマンドでpgpool-IIが管理しているPostgreSQLサーバの数を確認しましょう(図16)。
Usage: pcp_node_count timeout hostname port# username password timeout - connection timeout value in seconds. command exits on timeout hostname - pgpool-II hostname port# - pgpool-II port number username - username for PCP authentication password - password for PCP authentication -h - print this help タイムアウトtimeoutは適当な時間を設定してかまいません。 port番号は9898を指定します。 ユーザ名とパスワードは"pgpool2"を指定します。 今回はpostgres0とpostgres1の2つのnodeが接続されているので、"2"と表示されるはずです。 postgres@pgpool> pcp_node_count 10 192.168.1.200 9898 pgpool2 pgpool2 2 1.9.2 pcp_node_info次にpcp_node_infoコマンドで各ノードの情報を表示させます。 コマンドに与える引数は最後のnodeIDを除いてpcp_node_countコマンドと同じです(図17)。 pgpool-IIは各PostgreSQLサーバを"ノード"として管理していて、 サーバpostgres0はノード0、サーバpostgres1はノード1となっています。
Usage: pcp_node_info timeout hostname port# username password nodeID timeout - connection timeout value in seconds. command exits on timeout hostname - pgpool-II hostname port# - pgpool-II port number username - username for PCP authentication password - password for PCP authentication nodeID - ID of a node to get information for pcp_node_infoの出力は(表2)に示す4項目ですが、 重要なのは第3項目の"状態"(表3)です。
サーバpostgres0とpostgres1、つまりノード0とノード1の情報を表示してみます(図18)。 状態は共に2、つまりアイドルですが正常な状態です。状態が1か2ならば問題ありません。
postgres@pgpool> pcp_node_info 100 192.168.1.200 9898 pgpool2 pgpool2 0 192.168.1.100 5432 2 1073741823.500000 postgres@pgpool> pcp_node_info 100 192.168.1.200 9898 pgpool2 pgpool2 1 192.168.1.101 5432 2 1073741823.500000
ここで、ノード1のPostgreSQLを緊急停止しましょう。
停止モードオプション"-m"に"immediate"を設定すると、
接続しているセッションの有無にかかわらず、サーバが緊急停止します。
postgres@postgres1> pg_ctl -D /usr/local/pgsql/data -m immediate stop もう一度、ノード1のノード情報を調べましょう。状態が3で、切断されていることがわかります。 postgres@pgpool> pcp_node_info 100 192.168.1.200 9898 pgpool2 pgpool2 1 192.168.1.101 5432 3 1073741823.500000 1.9.3 pcp_detach_node, pcp_attach_node停止したノードを切り離すにはpcp_detach_nodeコマンド、 ノードを接続するにはpcp_attach_nodeコマンドを使います。 コマンド実行時の引数はpcp_node_infoコマンドと同じなので省略します。ノード1を切り離します。 postgres@pgpool> pcp_detach_node 100 192.168.1.200 9898 pgpool2 pgpool2 1 1.9.4 pcp_recovery_node最後に、オンラインリカバリを行うコマンドpcp_recovery_nodeです。 引数はpcp_node_infoコマンドと同じなので省略します。 ここでは、ノード1をリカバリします。postgres@pgpool> pcp_recovery_node 100 192.168.1.200 9898 pgpool2 pgpool2 1 リカバリ中にエラーが発生すれば、エラーメッセージが出力されます。 リカバリが正常に進行している間は一切メッセージを出力しないので、ちょっと不安になりますが、 実際の運用では設定ファイルpgpool.confでpgpool-IIのログを出力させて監視すれば問題ないでしょう。
オンラインリカバリが終了したら、pcp_attach_nodeコマンドでノード1を接続します。
そしてノード1の状態を調べ、オンラインリカバリが成功したことを確認しましょう。
postgres@pgpool> pcp_attach_node 100 192.168.1.200 9898 pgpool2 pgpool2 1 postgres@pgpool> pcp_node_info 100 192.168.1.200 9898 pgpool2 pgpool2 1 192.168.1.101 5432 1 1073741823.500000
1.10 まとめ以上、pgpool-IIを使ったレプリケーションと、 高可用性システムのためのオンラインリカバリについて説明しました。なお、これまで説明した構成では、 pgpool-IIが単一障害点となります。 これを避けるには、pgpool-IIを二重化してアプリケーションかロードバランサで負荷分散させるか(図19)、 pgpool-haとheartbeatで冗長化させるなどの方法があります(図20)。
pgpool-haに関する情報は http://pgpool.sraoss.jp/index.php?pgpool-HAを参照してください。
Last-modified: 2013-3-15
|