1. これは何？

このプログラム(pgpool-HA)は高可用性クラスタ構成ツール Hertbeat 2.x に対応した、
pgpool、pgpool-II むけエージェントスクリプトです。

Heartbeat 2.0以降にはCRM(Cluster Resource Manager)を使うことでサービス監視を
含むリソース管理を行ってくれるため、容易に高可用性サービスを立ち上げることが
可能になります。これとPostgreSQLのレプリケーションを実現するpgpoolを組み合わ
せることで、PostgreSQLサービスの冗長化をより簡単に行うことができます。

サービス図：

                              +---------+   +----------+
                             /|[pgpool] |---|PostgreSQL|
+------+     +----------+   / +---------+   +----------+
|client| --> |Virtual IP| --             \
+------+     +----------+   \ +---------+ \ +----------+
                             \|(pgpool) |  -|PostgreSQL|
                              +---------+   +----------+


本プログラムはHeartbeatと連携してpgpoolを高可用性対応するため、以下のコードが
含まれています。

 - Heartbeat 2.0以降で利用できるOCF形式のpgpool管理スクリプト
 - 管理スクリプト内で使用する監視プログラム


2. インストール

このプログラムを利用するためには少なくとも２台のマシンと、それぞれに以下の
ものがインストールされている必要があります。

- PostgreSQL(http://www.postgresql.org/) のクライアント
  psqlのみを必要とします。インストール時に環境変数PATHで参照可能な位置に
  配置してください。

- perl(http://www.perl.com/)
  perl 5以上とGetOpt::Longを必要とします。

- pgpool(http://pgpool.projects.postgresql.org/)
  インストール時に環境変数PATHで参照可能な位置に配置してください。
  設定ファイルについては指定しない場合インストール時のデフォルト位置になります。
  本バージョンの動作テストは pgpool-II 2.2.6 で行っています。
  show pool_status コマンドをサポートしている pgpool で動作するはずです。

- heartbeat 2.0以降(http://www.linux-ha.org/)
  本バージョンの動作テストは 2.1.4 で行っています。

また、導入先のホストに入っている必要はありませんが、以下のソフトウェアも必要に
なります。

- PostgreSQL 
  pgpoolが接続する先としてのPostgreSQLサーバーが必要になります。


2.2 インストール手順

基本的なプログラム、pgpool起動と監視スクリプトは以下の通りでインストール
できます。pgpool,psqlを環境変数PATHで参照できる形にしておいてください。

# ./configure
# cd src
# make
# make install

この時、OCF仕様のスクリプト"pgpool"が/usr/lib/orf/resource.d/heartbeat/以下に、
監視スクリプトpgpool.monitorがpgpoolと同じディレクトリにコピーされます。


2.3 heartbeatの設定

heartbeat上でpgpoolを稼働させるためにはheartbeat側の設定が必要になります。

- ha.cf
  crmを利用します。以下の一行を設定してください。

crm	true

- cib.xml
  cib.xml は heartbeat で crm を利用するために必要なファイルで、通常
  /var/lib/heartbeat/crm/ 以下に配置されています。サンプルとして
  1仮想IPアドレス、アクティブ/スタンバイのpgpool構成を行う cib.xml を
  以下に示します。

 <cib admin_epoch="0" epoch="0" num_updates="0">
   <configuration>
     <crm_config>
       <cluster_property_set id="cib-bootstrap-options">
         <attributes>
           <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="2.1.4-fb84f606a422 tip"/>
           <nvpair id="cib-bootstrap-options-default-resource-failure-stickiness" name="default-resource-failure-stickiness" value="0"/>
           <nvpair id="cib-bootstrap-options-default-resource-stickiness" name="default-resource-stickiness" value="100"/>
           <nvpair name="last-lrm-refresh" id="cib-bootstrap-options-last-lrm-refresh" value="1227682013"/>
           <nvpair id="cib-bootstrap-options-remove-after-stop" name="remove-after-stop" value="false"/>
         </attributes>
       </cluster_property_set>
     </crm_config>
     <nodes></node>
       <node id="cc18cfc5-68d7-45f8-a9e3-5364456e0721" uname="node2" type="normal">
         <instance_attributes id="nodes-cc18cfc5-68d7-45f8-a9e3-5364456e0721">
           <attributes>
             <nvpair id="standby-cc18cfc5-68d7-45f8-a9e3-5364456e0721" name="standby" value="off"/>
           </attributes>
         </instance_attributes>
       </node>
     </nodes>
     <resources>
       <primitive id="resource_ip" class="ocf" type="IPaddr" provider="heartbeat">
         <meta_attributes id="resource_ip_meta_attrs">
           <attributes>
             <nvpair id="resource_ip_metaattr_target_role" name="target_role" value="started"/>
           </attributes>
         </meta_attributes>
         <instance_attributes id="resource_ip_instance_attrs">
           <attributes>
             <nvpair id="0fc14517-1d8a-40d1-a1db-941cf14d9490" name="ip" value="192.168.0.3"/>
             <nvpair id="7ef81de0-2fed-4fae-a517-ac0b96adba4e" name="cidr_netmask" value="23"/>
             <nvpair id="754d986c-bb77-4028-98fa-5a222854001e" name="nic" value="eth0"/>
           </attributes>
         </instance_attributes>
         <operations>
           <op id="op_ip_start" name="start" timeout="90" start_delay="0" disabled="false" role="Started"/>
           <op id="op_ip_stop" name="stop" timeout="100" start_delay="0" disabled="false" role="Started"/>
           <op id="op_ip_mon" name="monitor" interval="5s" timeout="20s" start_delay="1s" disabled="false" role="Started"/>
         </operations>
       </primitive>
       <primitive id="resource_pgpool2" class="ocf" type="pgpool" provider="heartbeat">
         <meta_attributes id="resource_pgpool2_meta_attrs">
           <attributes>
             <nvpair id="resource_pgpool2_metaattr_target_role" name="target_role" value="started"/>
           </attributes>
         </meta_attributes>
         <instance_attributes id="resource_pgpool2_instance_attrs">
           <attributes>
             <nvpair id="5adb33f4-6641-41a2-be3d-31264c579a67" name="pgpoolconf" value="/var/lib/pgsql/pool_ha/pgpool.conf"/>
             <nvpair id="db163efd-0e00-41f1-9a4b-dfa3c5b299e0" name="pcpconf" value="/var/lib/pgsql/pool_ha/pcp.conf"/>
             <nvpair id="9f69680a-ca9c-44b5-9644-d35e1b0286d4" name="hbaconf" value="/var/lib/pgsql/pool_ha/pool_hba.conf"/>
             <nvpair id="1fabaefd-716d-4f6c-8827-0cd79e8505ae" name="logfile" value="/var/lib/pgsql/pool_ha/pgpool.log"/>
             <nvpair id="ff4d7726-7bc1-4f3d-8d0e-8bc4aafafbf7" name="pidfile" value="/tmp/pgpool.pid"/>
           </attributes>
         </instance_attributes>
         <operations>
           <op id="op_pool_mon" name="monitor" interval="10" timeout="20" start_delay="1m"/>
           <op id="op_pool_start" name="start" timeout="20"/>
           <op id="op_pool_stop" name="stop" timeout="20"/>
         </operations>
       </primitive>
     </resources>
     <constraints>
       <rsc_colocation id="colocation_poolip" from="resource_pgpool2" to="resource_ip" score="INFINITY"/>
       <rsc_location id="ip_ping_const" rsc="resource_ip">
         <rule id="prefered_ip_ping_const" score="-INFINITY" boolean_op="or">
           <expression attribute="pingd" id="ip_ping_rule_ex1" operation="not_defined"/>
           <expression attribute="pingd" id="13b33648-e266-4567-899d-d83ed66d3107" operation="lte" value="0" type="number"/>
         </rule>
       </rsc_location>
       <rsc_location id="cli-prefer-resource_ip" rsc="resource_ip">
         <rule id="prefered_cli-prefer-resource_ip" score="10">
           <expression attribute="#uname" id="0742b4b3-d70c-4f11-945a-cfdea8cf5ff8" operation="eq" value="node1"/>
         </rule>
       </rsc_location>
     </constraints>
   </configuration>
 </cib>


  この設定ファイル例によりpgpoolを管理できるようになります。
  この中で書き換える項目は以下の通りになります。

- ノード名
　サンプル中 node1、node2 と示されているのがノード名になります。ここでは
  ha.cf で指定してあるのと同じ名称を指定してください。

- IPアドレス
　サンプル中で 192.168.0.3 と示されているのが仮想IPアドレスです。
  ここに指定することでpgpoolが稼働中のホストに当該IPアドレスが割り振られます。

- 設定ファイル格納場所、その他オプション
  instance_attributes項目に以下の設定キーと値を指定することができます。

 設定キー    |	 説明
 ------------+----------------------------------------------------------
 pgpoolconf  | pgpool起動引数に指定する pgpool.conf のパス
 hbaconf     | pgpool起動引数に指定する pool_hba.conf のパス
 pcpconf     | pgpool起動引数に指定する pcp.conf のパス (pgpool-IIのみ)
 logfile     | pgpoolからリダイレクト出力するログファイル
 pidfile     | pgpoolのpidが記述されるファイルを指定
 options     | その他 pgpool の起動オプション "-d" など
 pgpooluser  | pgpoolを起動するユーザを指定、デフォルトは postgres

 この記述が終了したらファイルを heartbeat が利用する全てのサーバーに配置します。 cib.xml はサーバー間で全く同じである必要があります。なお、記述の検証には
 heartbeat に付属している crm_verify コマンドが使えます。

 crm_verify -X /var/lib/heartbeat/crm/cib.xml

 最後に全てが終わったら起動して確認します。

 # service heartbeat start

そのあとheartbeat自体の起動が終了まで数分待ち、psコマンドにてpgpoolが
起動していることを確認することができれば完了です。


2.3 active-active 構成について

pgpool-HA 1.1以降では、複数の設定ファイルが記述できるため、Active-Active構成
(相互のActive-Standby)を組むことが可能になります。type が pgpool である
リソースを複数記述します。それぞれ異なる設定ファイルに対応づけて、別ポートで
動作させます。


3. 利用方法

本ソリューションの起動及び終了は heartbeat 経由で自動で行われます。
順序としては以下の通りになります。

- PostgreSQLを起動

pgpoolで利用するPostgreSQLを起動します。

- heartbeatを起動

heartbeatを起動します。起動する場合はサービスとして

#service heartbeat start

と利用します。しばらくするとpgpoolが利用可能になります。この後、psql等で接続
するには cib.xml で指定したIPアドレスとpgpoolで指定したポートを指定します。
例えば先ほどのサンプルの場合

 psql -h 192.168.0.3 -p 9999

と実行すれば接続できます。

終了させる場合は、全く逆に全てのサーバーで heartbeat を終了させてください。
heartbeat の終了のためには以下の通りのコマンドを実行します。

# service heartbeat stop

heartbeatを稼働した状態で pgpool だけ停止させる場合には、リソースを停止する
heartbeatのコマンドを使用してください。

4. FAQ

- 接続できない
  以下の項目を確認してください。

-- heartbeatが起動しているか。

   起動していない場合、heartbeatのインストールか設定ファイルに問題があります。

-- heartbeatが起動していて、psの出力の中にcrmdが存在しているか

   crmdが立ち上がってない、終了した場合にはcib.xmlファイルの内容にエラーがある
   可能性があります。特に前回実行時の内容を署名していますので、.sigファイルが
   当該ディレクトリに存在している場合にはエラーになります。そのため、書き換え
   た場合には*.sigファイルを消去し、再度実行してみてください。

-- pgpoolが起動しているか。

   起動していない場合、pgpoolが単独で実行できるかどうかを確認してください。
   また、設定ファイルの内容も確認して下さい。

-- PostgreSQLが起動しているか。

   起動していない場合は立ち上げてください。

-- 浮動IPに対してping等でアクセスできるか。

   アクセスできない場合には設定ファイルを再度確認してください。


 なお、一度全てのホストでheartbeatを終了/起動させることで実行できることが
 あります。

- PGClusterのロードバランサーの冗長化に使えるか？
技術的には可能ですが、現在その設定に必要な内容が不足しているため、利用すること
はできません。このためには以下の作業が必要です。

-- pgpoolファイルを書き換え、pglbを起動終了させるようにする


5. 制限事項
・本プログラムに置ける監視はpgpoolの稼働チェック(pidファイルとSQL発行)のみ
  です。それ以外の異常状態（起動して、SQL文も受け付けるが異常が発生している
  ような場合など）には対応できません。
・PostgreSQL に対する管理は行っていません。
・PostgreSQL が全く起動していない状態は異常であるとみなし、pgpoolリソース
　は障害状態であると判断します。
・PostgreSQL がクラッシュした場合のリカバリは別途行う必要があります。
  この方法についてはpgpoolに準じます。
・pgpoolが複数インストールされている場合の挙動は、インストール時の $PATH に
  依存して決定します。他の種類のバイナリは管理できません。
  (実現するにはエージェントスクリプトを手修正して複数種類作ります)
・pgpool-II監視はpsqlで行われます。pcpを利用した監視はまだサポートされていま
  せん。

6. 著作権
本プログラムは谷田　豊盛（ゆたか） (tanida@sraoss.co.jp)がSRA OSS,Inc.日本支社
の後援の元作成し、pgpool global development groupに寄贈されました。ライセンスは
pgpoolに準じますが、詳細は付属のCOPYINGファイルを参照ください。

