[メモ] PostgreSQL+pgpool-II+heartbeat でクラスタリング/中編

[メモ] ++ でクラスタリング/中編

さて。前編からかな~~~り時間が経ってしまいました。

ということで今回は実際のインストールから設定内容をメモっておきたいと思います。

用意したもの

  • DBサーバ2台(検証環境:Fedora6(古) 実機:RHEL3(こっちも古))
  • PostgreSQL(都合により 7.4.x)
  • pgpool-II 2.1
  • pgpool-ha 1.1.0
  • heartbeat 2.1.3
  • libnet

当初はRPMでインストールしていましたが、最新バージョンにしたかったためソースからビルドすることにしました。設定ファイルやバイナリの場所は(個人的趣味により)基本的に /usr/local 以下としています。RPMインストールされる方や prefix を変更した場合は適宜読み替えてください。

インストール。

ということで、まずはガンガンインストールします。手順としては基本的に

tarball解凍→ configure → make → (make check|test) → make install

でいけると思われます。libnetは環境によってインストール済みかもしれません。

続いて各システムの設定に入ります。テスト環境での設定はこんな感じ。

DBノード(共通)

  • eth0 – サービス側
  • eth0:0 – pgpool 用 VIP
  • eth1 – バックエンド側

DBノードA

  • eth0 – 192.168.254.9
  • eth1 – 192.168.250.9

DBノードB

  • eth0 – 192.168.254.10
  • eth1 – 192.168.250.10

VIP – 192.168.254.20

PostgreSQLがListenするのは両ノードとも eth1(192.168.250.*)の 5432 ポートとします。pgpool は当然 eth0:0(192.168.250.20) の 5432 ポートを(あれば) Listen します。

いよいよ具体的な設定。。と言ってもテスト環境で試行錯誤した結果なので、正しい設定かどうか。。

まずはpgpool。

/usr/local/etc 以下に、pcp.conf/pgpool.conf/pool_hba.conf のサンプルが生成されますので、これを元に設定しました。

  • pcp.conf – pgpool コントロール用の認証設定を行うファイルです。USERID:PASSWORDというフォーマットで全ユーザ分をエントリします。パスワードはmd5ハッシュ値になりますので、pgpoolに同梱されているpg_md5コマンドの出力を利用しましょう。

pgsql:99836ad7731adb7e889def

admin:12ff87ebc86124ad7f88

  • pool_hba.conf – PostgreSQLの pg_hba.conf と同様、接続するクライアントに対するACLを設定します。詳細は割愛。。テスト環境だし。
  • pgpool.conf – 本命のpgpool設定ファイルです。サンプルから修正した内容を抜粋するとこんな感じ。

listen_address = ‘192.168.254.20’  # pgpool が Listen するインターフェース

port = 5432    # Listen するポート

replication_mode = true   # レプリケーション ON

load_balance_mode = true  # ロードバランス ON

replicate_select = true   # SELECT のレプリケート ON

health_check_period = 30  # 30秒ごとにヘルスチェック

health_check_user = ‘healthcheck’  # ヘルスチェックに使用するユーザ

# 以下、DBノードの設定。

backend_hostname0 = ‘nodeA’

backend_port0 = 5432

backend_weight0 = 1

backend_hostname1 = ‘nodeB’

backend_port1 = 5432

backend_weight1 = 1

ここで試しに PostgreSQL と pgpool を起動してみます。eth0:0 も手動でUPしておきます。当然PostgreSQLは両サーバ、pgpool はどちらか一方だけで。

起動した後、netstat でポート状況を確認してみます。

tcp        0      0 0.0.0.0:9898                0.0.0.0:*                   LISTEN

tcp        0      0 192.168.254.20:5432         0.0.0.0:*                   LISTEN

tcp        0      0 192.168.250.10:5432         0.0.0.0:*                   LISTEN

無事、192.168.254.20(eth0:0)と192.168.250.10の5432ポートがLISTENです。前者がpgpool、後者がPostgreSQLですね。9898ポートはpgpoolの管理用ポートです。

さて、続いて大物の設定に入ります。そう、heartbeat です。

僕も散々試行錯誤しググりまくりで、やっとここまで動作してくれるようになりました。が、設定内容が全ての場合において正しいというわけではないことだけご了承ください。

また、「ここはそうじゃなくてこうだろ」という突っ込みも絶賛お待ちしておりますm(_ _)m

まずは heartbeat の動作を決める設定ファイル、ha.cf

/usr/local/etc/ha.d 以下に作成します。/usr/local/share/doc/heartbeat-*/ にサンプルがありますので、コピーして編集しちゃいましょう。

僕の行った設定内容を抜粋するとこんな感じです。

# CRM(V2モード?) をON

crm  on

# heartbeat が使用するポート

udpport 694

# 他ノードへの通信は eth1 へのブロードキャストで。

bcast eth1

# 色々困るので自動復帰はナシ。

auto_failback off

# ノードの宣言。一行で「node  nodeA nodeB」でもOK

node  nodeA

node  nodeB

# NICの導通確認用に、クラスタ以外のノードを指定。

# 上位のスイッチやルータあたりが妥当かと。

ping 192.168.254.1

# pingで導通確認してくれる pingd を起動。

# 結果は default_ping_set という名前でCIBに格納させます。

respawn root /usr/local/lib/heartbeat/pingd -m 100 -d 5s -a default_ping_set

実際には上記の他、keepalive や各種タイムアウト値などの設定がありますが割愛。

ということで、ワクワクしながら heartbeat を起動。

crm_mon コマンドで heartbeat の状態が確認できますので、同時に起動しておくといいかも。

さて、ここから肝心のheartbeat監視内容を設定していきます。

CIBと呼ばれるXMLファイルが設定ファイルとなりますが、、、これが難しい。とりあえずあちこちから色々なパターンをかき集めてみました。こんな感じです。

<cib admin_epoch=”0″ num_updates=”0″ epoch=”1″ have_quorum=”true” cib_feature_revision=”1.0″>

<configuration>

<crm_config>

<cluster_property_set id=”deafult”>

<attributes>

<nvpair id=”symmetric_cluster” name=”symmetric-cluster” value=”true”/>

<nvpair id=”no_quorum_policy” name=”no-quorum-policy” value=”stop”/>

<nvpair id=”default_resource_stickiness” name=”default-resource-stickiness” value=”INFINITY”/>

<nvpair id=”stonith_enabled” name=”stonith-enabled” value=”false”/>

<nvpair id=”stop_orphan_resources” name=”stop-orphan-resources” value=”false”/>

<nvpair id=”stop_orphan_actions” name=”stop-orphan-actions” value=”true”/>

<nvpair id=”remove_after_stop” name=”remove-after-stop” value=”false”/>

<nvpair id=”short_resource_names” name=”short_resource_names” value=”true”/>

<nvpair id=”transition_idle_timeout” name=”transition-idle-timeout” value=”5min”/>

<nvpair id=”is_managed_default” name=”is-managed-default” value=”true”/>

</attributes>

</cluster_property_set>

</crm_config>

<nodes />

<resources>

<group id=”grp_pgpool”>

<primitive class=”ocf” id=”pgpool_if” provider=”heartbeat” type=”IPaddr”>

<operations>

<op id=”pgpool_if_mon” interval=”3s” name=”monitor” timeout=”5s” on_fail=”stop” />

</operations>

<instance_attributes id=”grp_pgpool_if_instance_att”>

<attributes>

<nvpair id=”pgpool_if_attr_ip” name=”ip” value=”192.168.254.20″ />

<nvpair id=”pgpool_if_attr_mask” name=”netmask” value=”24″ />

<nvpair id=”pgpool_if_attr_nic” name=”nic” value=”eth0″ />

</attributes>

</instance_attributes>

</primitive>

<primitive class=”ocf” id=”pgpool_proc” provider=”heartbeat” type=”pgpool”>

<operations>

<op id=”pgpool_proc_mon” interval=”3s” name=”monitor” timeout=”5s” on_fail=”stop” />

</operations>

<instance_attributes id=”grp_pgpool_proc_instance_att”>

<attributes>

<nvpair id=”pgpool_conf_path” name=”pgpoolconf” value=”/usr/local/etc/pgpool.conf” />

<nvpair id=”pcp_conf_path” name=”pcpconf” value=”/usr/local/etc/pcp.conf” />

<nvpair id=”log_file_path” name=”logfile” value=”/var/log/pgpoolhb.log” />

</attributes>

</instance_attributes>

</primitive>

</group>

</resources>

<constraints>

<rsc_location id=”rsc_location_pingd” rsc=”grp_pgpool”>

<rule id=”rscloc_pingd” score_attribute=”default_ping_set”>

<expression id=”rscloc_pingd_1_defined” attribute=”default_ping_set” operation=”defined” />

</rule>

</rsc_location>

<rsc_location id=”rsc_location_grp_pgpool” rsc=”grp_pgpool”>

<rule id=”rscloc_grp_pgpool_1″ score=”100″>

<expression attribute=”#uname” id=”rscloc_grp_pgpool_1_exp” operation=”eq” value=”nodeA” />

</rule>

<rule id=”rscloc_grp_pgpool_2″ score=”-INFINITY” boolean_op=”or”>

<expression attribute=”default_ping_set” id=”rscloc_grp_pgpool_2_undefined” operation=”not_defined” />

<expression attribute=”default_ping_set” id=”rscloc_grp_pgpool_2_zero” operation=”lte” value=”0″ />

</rule>

</rsc_location>

</constraints>

</configuration>

</cib>

このファイルで設定している(つもりの)内容は、

  • 監視するリソースは、pgpool_if と pgpool_proc の2つ。
  • pgpool_if は VIP を持つ eth0:0
  • pgpool_proc は pgpool プロセス
  • pgpool_if と pgpool_proc はりソースグループ grp_pgpool に属しており、pgpool_proc より先に pgpool_if がOKである必要がある。

これに、下記の制約事項を設定しています。

  • 自ノード名が nodeA ならばスコアに+100。同時に両ノードがリソースを起動しないよう、片方のノードを若干優先させる。
  • default_ping_set(pingdが設定)がnot definedもしくは0以下の場合はスコアを -INFINITY とし、リソースを停止させる。

こんな内容で初期CIB.xmlを作成します。crm_verify コマンドで内容の検証ができますので、エラーや警告をつぶしてしまいましょう。

# crm_verify -Vx CIB.xml

いよいよheartbeatに作成したCIBを「喰わせ」ます。heartbeatはこのXMLファイルから独自のデータベースを構築しますので、変更した場合は食わせなおす必要があります。

なお、CIBは全ノードで同期されますので、XMLファイルを食わせるのは「マスター」となっているノードだけでOKです。ちなみにどのノードがマスターなのかを調べるには cibadmin コマンドを使います。

[root@nodeB]# cibadmin -m

CIB on localhost is _not_ the master instance

[root@nodeA]# cibadmin -m

CIB on localhost _is_ the master instance

上記の例だと nodeA がマスターですね。

ということで、マスターノードでCIBを食わせます。CIB食らえコマンドも cibadmin です。

[root@nodeA]# cibadmin -Mx CIB.xml

内容に問題がなければheartbeatのCIBデータベースが更新され、各ノードに同期されるはず。crm_mon コマンドの出力にリソースグループやリソース名が表示され、 Started **** と出ていればOKです!

Refresh in 4s…

============

Last updated: Thu Sep 25 18:20:19 2008

Current DC: nodeA (32dda351-1ee4-4424-9681-07f057c46449)

2 Nodes configured.

1 Resources configured.

============

Node: nodeA (32dda351-1ee4-4424-9681-07f057c46449): online

Node: nodeB (9c351263-29ab-4c70-8a64-79a5fb4478d7): online

Resource Group: grp_pgpool

pgpool_if   (heartbeat::ocf:IPaddr):        Started nodeA

pgpool_proc (heartbeat::ocf:pgpool):        Started nodeA

この例だと nodeA がDC(メインコントローラ)で、pgpool_if/pgpool_proc も nodeA で起動されています。

ということでnodeAで確認。

# /sbin/ifconfig eth0:0

eth0:0    Link encap:Ethernet  HWaddr 00:03:47:78:FC:8F

inet addr:192.168.254.20  Bcast:192.168.254.255  Mask:255.255.255.0

UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

お、eth0:0 がUPされ、VIPが設定されています^^

# ps -aef |grep pgpool

postgres  2654     1  0 16:29 ?        00:00:00 /usr/local/bin/pgpool -f /usr/local/etc/pgpool.conf -a /usr/local/etc/pool_hba.conf -F /usr/local/etc/pcp.conf -d -n

postgres  2667  2654  0 16:29 ?        00:00:00 pgpool: wait for connection request

postgres  2668  2654  0 16:29 ?        00:00:00 pgpool: wait for connection request

postgres  2671  2654  0 16:29 ?        00:00:00 pgpool: wait for connection request

postgres  2672  2654  0 16:29 ?        00:00:00 pgpool: wait for connection request

:

:

pgpool も起動しています!!試しに他のマシンからpsqlで接続してみましょう!

% psql -h 192.168.254.20 -U pgsql -p -l

Password:

List of databases

Name     |    Owner    | Encoding

————-+————-+———-

healthcheck | healthcheck | EUC_JP

pgpool      | pgsql       | EUC_JP

template0   | pgsql       | EUC_JP

template1   | pgsql       | EUC_JP

testdb      | pgsql       | EUC_JP

おー、接続できていますね!あとは実際にCREATE TABLEしたりINSERTしたりSELECTしてみましょう。PostgreSQLのログ出力をONにして、両サーバで眺めていると面白いですよ^^)b

今回は SELECT もレプリケートするよう設定していますが、場合によってはレプリケートしない方がいいことがあるようです。この辺は現在調査中・・・・

ということで、ここまでが正常系。

あとは順次、

  • 稼動中のPostgreSQLをkillしてみる
  • 稼動中のpgpoolをkillしてみる
  • リソース稼動中マシンのeth0側ネットワークケーブルを引っこ抜く
  • リソース稼動中マシンをshutdownしてみる

等のテストを行い、きちんとリソースが再起動もしくは他のマシンで起動(フェイルオーバ)するか確認すれば、第一段階はOKと言えるでしょう^^

ということで、次はいよいよ実装・・・・と行きたいところですが、ここで一つ問題が発生しました。既存のシステムで、いくつかpgpoolが対応できない、もしくは不具合となりそうな機能を使っているものがあるようなのです。

ということで、既存システムの全プログラムをチェックすることと相成りました。。。。。何個あるんだろう。。。。orz

次回はチェック/修正で学んだこと・修正内容をまとめていけたらいいなぁ、なんて思ってます。

それではまた次回。。。は、いつになるのやら。

  1. コメント 0

  1. 2013 09/25
    トラックバック先:PGPOOL with clustering | ycnote

return top