[メモ] 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 のレプリケート ONhealth_check_period = 30 # 30秒ごとにヘルスチェック
health_check_user = ‘healthcheck’ # ヘルスチェックに使用するユーザ# 以下、DBノードの設定。
backend_hostname0 = ‘nodeA’
backend_port0 = 5432
backend_weight0 = 1backend_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): onlineResource 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
次回はチェック/修正で学んだこと・修正内容をまとめていけたらいいなぁ、なんて思ってます。
それではまた次回。。。は、いつになるのやら。
タグ: DBクラスタ, heartbeat, Linux, pgpool-II, PostgreSQL
