pgpool-II 3.2 の新機能 (3) Watchdog

pgpool-II 3.2 の新機能 (3) Watchdog

SRA OSS, Inc. 日本支社
長田 悠吾

watchdog とは

従来の pgpool-II で複数の PostgreSQL を連携させる場合、pgpool-II 自体、あるいは pgpool-II が動いているサーバや OS に障害が発生すると全体のサービスが停止してしまうため、ここが単一障害点(Single Point Of Failure: SPOF)となっていました。watchdog は、複数の pgpool-II の連携によってこの問題を解決し、pgpool-II の可用性を高める機能です。この機能により、サービスを提供する主系(アクティブ)の pgpool-II に障害が発生した場合でも、それを検知した待機系(スタンバイ)の pgpool-II が主系に取って代わって運用を継続する、すなわち pgpool-II のフェイルオーバが実現可能になりました。

今まではこのような構成をとるためには pgpool-HA というパッケージが別に必要でしたが、pgpool-II 3.2 では pgoool-II 自身がこの機能を持つようになりました。また、複数の pgpool-II を同時に利用するいわゆる「マルチマスタ」的な使い方もできるようになりました。この構成についても 後で説明 します。

1. watchdog の概要

watchdog は pgpool-II 本体から起動される子プロセスとして、以下の機能を提供します。

1.1. pgpool-II サービスの死活監視

watchdog は pgpool-II の「プロセス」そのものではなく、pgpool-II の「サービス」を監視します。プロセス自体が起動していても、サービスが提供できない pgpool-II は「ダウンしている」と見なされます。具体的には、監視対象の pgpool-II へクエリ(デフォルトでは "SELECT 1")を発行しその応答をチェックすることで、その pgpool-II がサービスを提供可能かどうかを判断します。

また watchdog は、pgpool-II から上位のサーバ(アプリケーションサーバなど)への接続も監視します。具体的には、上位サーバへ発信した ping の応答が無い場合には、その pgpool-II は上位サーバへサービスを提供できない状態(ダウン状態)であると判断されます。

なお、これは pgpool-II の従来からの機能である「ヘルスチェック」とは別の機能です。 watchdog の死活監視は pgpool-II サービスの監視を行う機能である一方で、ヘルスチェックは定期的にバックエンドのデータベースに接続を試みて障害発生の有無を検知する機能です。 ヘルスチェックに関して詳しくは こちらの記事 をご参照下さい。

1.2. 相互監視と情報共有

各 watchdog は自身の親プロセスである pgpool-II を監視するだけではなく、クラスタを構成している他の全ての pgpool-II を監視します。また、watchdog 間でお互いのサーバの情報を交換し合うことにより、サーバ情報を最新に保ちます。

1.3. 障害発生検知時のアクティブ/スタンバイ切り替え

pgpool-II が動いているサーバや OS、ネットワークの障害による pgpool-II サービスダウンは watchdog の相互監視により検出されます。また、自分自身の pgpool-II サービスがダウンした場合、watchdog は他の watchdog へそれを通知します。アクティブだった pgpool-II がダウンした場合、他の watchdog は新しいアクティブを投票で決め、アクティブ/スタンバイの切り替えを行います。

1.4. 仮想 IP アドレスの自動付け替え

アクティブな pgpool-II は仮想 IP で接続を受け付けます。スタンバイ pgpool-II が新しいアクティブに昇格する時に、新アクティブ機の watchdog はアクティブ用の仮想 IP インターフェースを起動します。 一方、旧アクティブ機の watchdog はアクティブ用仮想 IP インターフェースを停止します。これにより、サーバが切り替わった後も新アクティブ機は同じ IP アドレスを使ってサービスを継続します。

1.5. スタンバイ機としての自動登録

サーバの起動時に watchdog は自分自身のサーバ情報を他の watchdog に通知し、その応答として他の watchdog から監視対象となっている全サーバの情報を受け取ります。それに伴い、サーバはスタンバイ機として自動的にクラスタに追加されます。

2. 全体構成

watchdog プロセスを含む pgpool-II サーバは以下の図のようなシステム構成をとります。(pgpool-II が2台の場合の例です)

3. 設定方法

クラスタを構成する全ての pgpool-II で pgpool.conf の設定を行う必要があります。ここでは2台の pgpool-II を2台のサーバ(server1, server2)で動かす場合を例に説明します。

まず、watchdog 機能を有効にするフラグ use_watchdog を on にします。

use_watchdog = on
                                    # Activates watchdog

3.1. 上位サーバ

pgpool-II のサービス提供先(DB クライアント)のサーバを、上位サーバと呼びます。 pgpool-II のプロセスが生きていて PostgreSQL と繋がっている場合でも、 上位サーバとのリンクが切れていれば pgpool-IIは「サービス」を継続できません。 そのため、watchdog は上位サーバとのリンクが繋がっているかどうかも監視します。

上位のサーバのリストは trusted_servers に指定します。複数のホスト名または IP アドレスをカンマ区切りで指定できます。空欄あるいは指定なしの場合には上位サーバへの接続監視は行いません。ここでは空欄にしておきます。

trusted_servers = ''
                                    # trusted server list which are used
                                    # to confirm network connection
                                    # (hostA,hostB,hostC,...)

3.2. 仮想 IP

アクティブ機が立ち上げる仮想 IP を delegate_IP に指定します。まだ他のノードで使われてない IP アドレスを記述します。またクラスタを構成する pgpool-II で共通の IP アドレスを指定してください。

すでに使用済みの IP アドレスが指定された場合、及び、pgpool-II 間で異なる IP アドレスが指定された場合には pgpool-II は起動しません。ここでは以下のように設定します。

delegate_IP = '133.137.177.222'
                                    # delegate IP address

3.3. watchdog サーバ

watchdog が他の watchdog から情報を受け取るためのホスト名または IP アドレスを wd_hostname、ポート番号を wd_port に指定します。

wd_hostname は他のサーバとの弁別のために必要です。省略した場合には hostname コマンドの結果が使われますが、出来る限り明示的に指定することをお勧めします。ここではそれぞれ server1, server2 を指定します。wd_port はデフォルト値の 9000 にしておきます。

  • server1
    wd_hostname = 'server1'
                                        # Host name or IP address of this watchdog
    wd_port = 9000
                                        # port number for watchdog service
    
  • server2
    wd_hostname = 'server2'
                                        # Host name or IP address of this watchdog
    wd_port = 9000
                                        # port number for watchdog service
    

3.4. 監視対象サーバ関連

監視対象の pgpool-II が稼働するホスト名を other_pgpool_hostname0 に、その pgpool-II のポート番号を other_pgpool_port0 に、その watchdog のポート番号 other_wd_port0 にそれぞれで記述します。 監視対象を複数指定する場合は、other_pgpool_hostname1, other_pgpool_port1, other_wd_port1 といった感じに数字部分を連番にして続けます。

ここでは自分以外の監視対象サーバは1つだけなので、0 番目のオプションのみ指定します。

  • server1
    other_pgpool_hostname0 = 'server2'
                                        # Host name or IP address to connect to for other pgpool 0
    other_pgpool_port0 = 9999
                                        # Port number for othet pgpool 0
    other_wd_port0 = 9000
                                        # Port number for othet watchdog 0
    
  • server2
    other_pgpool_hostname0 = 'server1'
                                        # Host name or IP address to connect to for other pgpool 0
    other_pgpool_port0 = 9999
                                        # Port number for othet pgpool 0
    other_wd_port0 = 9000
                                        # Port number for othet watchdog 0
    

4. 使用方法

以降は、実際に watchdog を動かしその機能を確認していきます。クエリの実行の様子をログで確認するために log_statement オプションを on にしておきます。

log_statement = on
                                   # Log all statements

4.1. watchdog プロセスの起動

4.1.1. アクティブ pgpool-II の起動

watchdog は pgpool-II を起動すると、自動的にその子プロセスとして起動されます。ただし、watchdog 使用時は仮想 IP インタフェースの起動・停止を行うため、pgopol-II の起動は root 権限で行う必要があります*1)

起動した pgpool-II がアクティブ/スタンバイのどちらになるかは起動順で決まります。一番最初に起動した pgpool-II がアクティブ、それ以降に起動した pgpool-II はスタンバイとなります。ここでは server1 の pgpool-II を先に起動します。

(server1) $ sudo bin/pgpool -n >pgpool.log 2>&1

server1のログに以下のメッセージが出力されます。

LOG:   pid 30482: wd_create_send_socket: connect() reports failure (Connection refused).
                  You can safely ignore this while starting up.
LOG:   pid 30482: wd_escalation: escalated to master pgpool
LOG:   pid 30482: wd_create_send_socket: connect() reports failure (Connection refused).
                  You can safely ignore this while starting up.
LOG:   pid 30482: wd_escalation:  escaleted to delegate_IP holder
LOG:   pid 30482: wd_init: start watchdog
LOG:   pid 30482: pgpool-II successfully started. version 3.2.0 (namameboshi)
LOG:   pid 30482: find_primary_node: primary node id is 1

これから、server1 がアクティブ(ログ中では master と出力されています)として起動し、仮想 IP を保持していること, pgpool-II, watchdog 共に正しく起動していることがわかります。1行目と3行目に Connection refused と出力されているのは、監視対象である server2 の pgpool-II がまだ起動していないためであり、ここでは無視してかまいません。

watchdog は上位サーバへの接続、及び、監視対象の pgpool-II の起動を待ってから死活監視を開始します。 この段階では server2 の pgpool-II が起動していないので死活監視はまだ始まっていません。

*1) setuid を利用して一般ユーザから起動する方法もあります。これについては 後述 します。
4.1.2. スタンバイ pgpool-II の起動:死活監視開始

次に server2 の pgpool-II を起動します。

(server2) $ sudo bin/pgpool -n >pgpool.log 2>&1

以下のようなログが出力されます。

LOG:   pid 7145: wd_init: start watchdog
LOG:   pid 7145: pgpool-II successfully started. version 3.2.0 (namameboshi)
LOG:   pid 7145: find_primary_node: primary node id is 1
・・・
LOG:   pid 7148: watchdog: lifecheck started

watchdog, pgpool-II が正常に起動し、死活監視(lifecheck)が開始されたことがわかります。 その後、server1 のログにも死活監視開始のメッセージが出力されます。

LOG:   pid 30488: watchdog: lifecheck started
4.1.3. 死活監視が始まらないとき

watchdog が正しく働いてないように見える場合には、ログを確認して死活監視が始まっているかどうかをチェックしてください。

死活監視が始まらない場合は、ホスト名やポート番号の指定は正しいか、サーバ間のネットワークに問題はないか、ファイアウォールが邪魔をしていないか等を確認してみてください。

4.2. watchdog 起動時のエラー

下記の場合にはエラーとなり、pgpool-II は起動せずに終了してしまいます。

root 権限がない場合

以下のメッセージを出力して終了します。

ERROR: pid 25186: watchdog must be started under the privileged user ID to up/down virtual network interface.
起動時に上位サーバに接続できない場合

以下のメッセージを出力して終了します。

ERROR: pid 25194: wd_init: failed to connect trusted server
ERROR: pid 25194: watchdog: wd_init failed
ERROR: pid 25194: wd_main error
delegate_IP に既存の IP が指定されている場合

以下のメッセージを出力して終了します。

ERROR: pid 25203: wd_init: delegate_IP already exists
ERROR: pid 25203: watchdog: wd_init failed
ERROR: pid 25203: wd_main error
pgpool-II 間で仮想 IP の指定が異なる場合

2台目以降に起動した pgpool-II の delegate_IP が最初に起動した pgpool-II の delegate_IP と異なる場合、後から起動した pgpool-II は以下のメッセージを出力して終了します。

ERROR: pid 15406: wd_init: failed to start watchdog
ERROR: pid 15406: watchdog: wd_init failed
ERROR: pid 15406: wd_main error

また、最初に起動した pgpool-II のログには以下のメッセージが出力されます。

ERROR: pid 25261: wd_set_wd_list: delegate IP mismatch error
設定ファイルの不備

仮想 IP の指定、監視対象 pgpool-II の指定がされていない場合、以下のメッセージを出力して終了します。

ERROR: pid 15458: watchdog: wd_check_config failed
ERROR: pid 15458: wd_main error

4.3. 接続の確認

server1 で ifconfig コマンドを実行して、delegate_IP で指定した仮想 IP が立ち上がっていることを確認します。

(server1) $ /sbin/ifconfig

eth0   ・・・
・・・
eth0:0    Link encap:Ethernet  HWaddr 00:1E:C9:xx:xx:xx
	  inet addr:133.137.177.222  Bcast:133.137.177.255  Mask:255.255.255.0
・・・

また、psql で仮想 IP に接続し、アクティブである server1 の pgpool-II でクエリが実行されることを確認します。

$ psql -h 133.137.177.222 -p 9999 -U postgres -c “SELECT 'test query'”

server1 のログに以下のように出力されます。

LOG:   pid 30959: statement: SELECT 'test query'

4.4. watchdog の停止とアクティブ/スタンバイの切り替え

pgpool-II を停止すると watchdog も停止します。watchdog は停止する直前に「自分がダウンすること」を他の pgpool-II へ通知します。また、アクティブの場合には仮想 IP インタフェースを停止させます。

Ctrl-C で server1 の pgpool-II を停止させます。すると server1 では以下のログが出力されます。

LOG:   pid 30482: received fast shutdown request
LOG:   pid 30482: watchdog_pid: 30488
LOG:   pid 30488: wd_IP_down: ifconfig down succeeded

server1 からダウン通知を受け取った server2 はスタンバイからアクティブに昇格します。 server2 には以下のログが出力されます。

LOG:   pid 7147: wd_escalation: escalated to master pgpool
・・・
LOG:   pid 7147: wd_escalation:  escaleted to delegate_IP holder

psql で仮想 IP に接続すると、クエリは server2 で実行されることを確認します。

$ psql -h 133.137.177.222 -p 9999 -U postgres -c “SELECT 'test query'”

server2 のログに以下のように出力されます。

LOG:   pid 8189: statement: SELECT 'test query'

4.5. pgpool-II の再起動

先ほど停止させた server1 の pgpool-II を再度スタンバイとして起動させます。

(server2) $ sudo bin/pgpool -n >pgpool.log 2>&1

server1 のログには以下が出力され、死活監視が再び開始されたことが確認できます。

LOG:   pid 31442: wd_init: start watchdog
LOG:   pid 31442: pgpool-II successfully started. version 3.2.0 (namameboshi)
LOG:   pid 31442: find_primary_node: primary node id is 1
・・・
LOG:   pid 31445: watchdog: lifecheck started

4.6. ネットワーク遮断

先ほどは pgpool-II を停止した場合のアクティブ/スタンバイの切り替わりを確認しました。今度はネットワーク障害が発生した場合に、アクティブ/スタンバイが切り替わることを実験してみます。

現在スタンバイである server1 からアクティブである server2 への接続が遮断された状況をシミュレートするため、server1 の /etc/hosts を以下のように編集して、ホスト名 server2 に無効な IP アドレスを対応付けます。

(server1) $ sudo vi /etc/hosts

# 133.137.177.200 はノードに対応付けられていない無効なIPアドレス
133.137.177.200 server2

こうするとホスト名 server2 の名前解決が正しく出来なくなり死活監視の応答がなくなります。これは、server1 から見ると server2 の pgpool-II がダウンしているように見えます。そのため、server1 の pgpool-II は新アクティブに昇格しようとします。/etc/hosts の書き換えからしばらくすると、server1 のログに以下のメッセージが出力され、server1 の pgpool-II がアクティブに昇格したことが確認できます *2)

 

LOG:   pid 31445: wd_lifecheck: lifecheck failed 3 times. pgpool seems not to be working
LOG:   pid 31445: wd_escalation: escalated to master pgpool
・・・
LOG:   pid 31445: wd_escalation:  escaleted to delegate_IP holder
*2) 実はこの状態はアクティブな pgpool-II が複数できてしまっている「スプリットブレイン」と呼ばれる状態です。しかし実際には2つの pgpool-II の間の接続「だけ」が遮断されるということはあまり無いので、今回の実験のために用意した特殊な状況であると言えます。watchdog のスプリットブレイン対策についてはま た後で説明 します。

5. 内部構造

以降は watchdog の動作について詳細に説明します。

5.1. 死活監視

死活監視の振る舞いは以下のパラメータで指定できます。

wd_interval = 10
                                    # lifecheck interval (sec) > 0
wd_life_point = 3
                                    # lifecheck retry times
wd_lifecheck_query = 'SELECT 1'
                                    # lifecheck query to pgpool from watchdog

死活監視は wd_interval 秒ごとに1回、監視対象の pgpool-II に対して wd_lifecheck_query に指定したクエリを実行し、その応答をチェックします。wd_life_point に指定した回数だけクエリ実行を失敗し場合に、その監視対象はサービス提供ができない状態(ダウン状態)とみなされます。

また死活監視のタイミングで上位サーバへの接続もチェックされます。trusted_servers に指定したサーバ群に対して、ping を実行します。どのサーバからも応答が帰ってこなかった場合、watchdog は自身をダウンしたものと見なします。

ping コマンドのパスは ping_path パラメータで指定できます。

ping_path = '/bin'
                                    # ping command path

以上のパラメータは通常はデフォルトのままで問題ありません。

5.2. アクティブ/スタンバイの切り替え

5.2.1. 死活監視の結果に基づく動作

死活監視の結果に基づき watchdog は以下のように振舞います。

自分自身がダウンした場合
そのことを他の pgpool-IIに通知します。
自分以外のアクティブな pgpool-II がダウンした場合
起動したのが一番古い最古参の pgpool-II が新しい アクティブ に立候補します。もし他にアクティブな pgpool-II がいない場合、立候補した pgpool-II が新しいアクティブに昇格します。
自分がダウン状態から復帰したとき
そのことを他の pgpool-II に通知します。もし他にアクティブな pgpool-II がいない場合には新しいアクティブに昇格します。
5.2.2. 他の pgpool-II からの通知に基づく動作

以下は、他の pgpool-II からの通知を受けてアクティブ/スタンバイを切り替えるケースです。

他の pgpool-II のダウン通知を受信した場合
自分が最古参の場合にはアクティブに昇格します。
他の pgpool-II がアクティブに昇格した場合
自分がアクティブであった場合にはスタンバイに降格します。そうすることで、アクティブが複数になることを回避します*3)
*3) 例えば、たまたま同時刻に起動した pgpool-II が同時にアクティブになろうした場合、瞬間先に起動した方が先にアクティブになります。 しかしそのすぐ直後、ほんの僅かに遅れて起動した pgpool-II が新しいアクティブとなり、それを受けて、先に起動した pgpool-II はスタンバイに降格します。
5.2.3. pgpool-II ステータスの確認

pgpool-II がアクティブか、スタンバイか、ダウンかといったステータスは、死活監視のタイミングで DEBUG レベルのログに出力されます*4)

以下は server1 のログ出力の例です。

DEBUG: pid 852: wd_lifecheck: checking pgpool 0 (server1:9999)
DEBUG: pid 852: wd_lifecheck: OK, status: 3
DEBUG: pid 852: wd_lifecheck: checking pgpool 1 (server2:9999)
DEBUG: pid 852: wd_lifecheck: OK, status: 2

status: の後ろの数字がステータスを表し、1: 初期状態、2: スタンバイ、3: アクティブ、4: ダウン、を表します。すなわち、このログは

  0 番目(自分自身)の pgpool 1 番目の pgpool
ホスト名 server1 server2
ポート番号 9999 9999
ステータス アクティブ(3) スタンバイ(2)

であることを意味します。また、OK は死活監視のクエリ実行が成功したことを意味します。クエリ実行が失敗した場合には NG と出力され、残りの死活監視の回数が出力されます。一定回数以上クエリ実行に失敗するとステータスがダウン(4)に変化します。

以下は server2 への接続が遮断されたときの server1 のログの例です。

DEBUG: pid 852: wd_lifecheck: checking pgpool 0 (server1:9999)
DEBUG: pid 852: wd_lifecheck: OK, status: 3
DEBUG: pid 852: wd_lifecheck: checking pgpool 1 (server2:9999)
DEBUG: pid 852: wd_lifecheck: NG, status: 2 life:3
DEBUG: pid 852: wd_lifecheck: checking pgpool 0 (server1:9999)
DEBUG: pid 852: wd_lifecheck: OK, status: 3
DEBUG: pid 852: wd_lifecheck: checking pgpool 1 (server2:9999)
DEBUG: pid 852: wd_lifecheck: NG, status: 2 life:2
DEBUG: pid 852: wd_lifecheck: checking pgpool 0 (server1:9999)
DEBUG: pid 852: wd_lifecheck: OK, status: 3
DEBUG: pid 852: wd_lifecheck: checking pgpool 1 (server2:9999)
DEBUG: pid 852: wd_lifecheck: NG, status: 2 life:1
LOG:   pid 852: wd_lifecheck: lifecheck failed 3 times. pgpool seems not to be working
DEBUG: pid 852: wd_lifecheck: checking pgpool 0 (server1:9999)
DEBUG: pid 852: wd_lifecheck: OK, status: 3
DEBUG: pid 852: wd_lifecheck: checking pgpool 1 (server2:9999)
DEBUG: pid 852: wd_lifecheck: NG, status: 4 life:0
LOG:   pid 852: wd_lifecheck: lifecheck failed 3 times. pgpool seems not to be working
*4) DEBUG レベルのログを出力するには pgpool の起動オプション「-d (--debug)」が必要です。

5.3 情報共有の詳細

5.3.1. サーバ情報の共有

watchdog は自分を含む監視対象サーバの情報を保持しており、それを互いに交換・共有しています。個々のサーバ情報は具体的には以下の通りです。

  • ホスト名
  • pgpool のポート番号
  • watchdog のポート番号
  • ステータス(アクティブ / スタンバイ / ダウン など)
  • 仮想 IP の情報
  • 起動時刻

watchdog は起動時に、他の監視対象のサーバ情報をまとめて受け取ります。また、起動時や停止時、アクティブへの昇格時など、他の watchdog と通信する際にもサーバ情報の送受信が行われます。

5.3.2. DB ノード状態の共有

複数の pgpool-II で複数の PostgreSQL を共有している場合、pgpool-II 間で DBノードの状態が共有されている必要があります。例えば、1つの pgpool-II である DB を切り離した場合、他の pgpool-II でも同じ DB を切り離しておかなければ DB 間で一貫性が失われる恐れがあります。

このため、watchdog は1台の pgpool-II で実行された failover command(ノードの追加、切り離しなど)を他の全ての pgpool-II で実行します。failover command が実行されると、watchdog は以下の情報を他の pgpool-II へ通知します。

  • コマンド種別(以下のどれか)
    • attach: ノードの追加
    • detach: ノード切り離し
    • promote: プライマリへの昇格
  • 対象ノードのリスト

実際の振る舞いを確認してみます。server1, server2 の2つの pgpool-II が2台の PostgreSQL ノード(db1, db2)を共有しているとします。まずは pcp_node_info コマンドでそのことを確認します。

$ pcp_node_info 0 server1 9898 postgres pass 0
db1 5432 2 0.500000
$ pcp_node_info 0 server1 9898 postgres poss 1
db2 5432 2 0.500000
$ pcp_node_info 0 server2 9898 postgres pass 0
db1 5432 2 0.500000
$ pcp_node_info 0 server2 9898 postgres pass 1
db2 5432 2 0.500000

次に pcp_dertach_node コマンドで、server1のノード0番(db1)を切り離します。

$ pcp_detach_node 0 server1 9898 postgres pass 0

server1, server2 の両方でノード 0 番(db1)が切り離されている(状態が 3 になっている)ことを確かめます。

$ pcp_node_info 0 server1 9898 postgres pass 0
db1 5432 3 0.500000
$ pcp_node_info 0 server1 9898 postgres pass 1
db2 5432 2 0.500000
$ pcp_node_info 0 server2 9898 postgres pass 0
db1 5432 3 0.500000
$ pcp_node_info 0 server2 9898 postgres pass 1
db2 5432 2 0.500000
5.3.3. リカバリ開始・終了タイミングの通知

pgpool-II は レプリケーションモードの オンラインリカバリ(2nd ステージ)を行っている最中は新しい接続を受け付けないようになっています。watchdog で複数の pgpool-II が 複数の PostgreSQL を共有する場合も、DB 状態の一貫性を保つため、1つの pgpool-II でオンラインリカバリの 2nd ステージが始まると他の pgpool-II でも新しい接続を受け付けなくなります。watchdog はリカバリの開始と終了のタイミングを他の pgpool-II へ通知することでこの機能を実現しています。

5.3.4. マルチマスタ構成

以上のように pgpool-II 間で DB ノードの状態が共有されることを利用して、複数の pgpool-II を同時に利用するマルチマスタ構成をとることが可能です。この構成は主に負荷分散を目的としており、下図のように複数のアプリケーションが仮想 IP ではなく固有 IP を介して別々の pgpool-II に接続します。

5.4. スプリットブレイン対策

複数の pgpool-II の間のネットワークが遮断された場合、互いに「ダウンしたのは相手である」と判断するため、結果としてアクティブの pgpool-II が複数できてしまうことが起こり得ます。この状況をスプリットブレイン(分離脳)と呼びます。

watchdog では 上位サーバへの接続をチェックすることでスプリットブレイン対策を行っています。下図は pgpool-II 間の接続が遮断された状況の例です。赤い×印の所でネットワーク障害が起きているため、server2 は上位サーバとの接続を確認できません。server1 はサービス提供可能ですが、server2 はサービス提供ができない状態です。この場合アクティブになるのは server1 の方が妥当です。このように、上位サーバへの接続(ping)が確認できない場合には「ダウンしているのは自分自身である」と判断し、あえてアクティブに昇格しないことで、watchdog はスプリットブレインを回避しています。 *5)

*5) ただしこの方法は、watchdog 間の通信経路「のみ」が遮断された場合(例えば、特定ポート番号でのネットワーク障害など)に発生し得るスプリットブレインへの対策とはなっていません。

5.5. 仮想 IP の制御

watchdog は仮想 IP インタフェースの起動/停止のために ifconfig コマンドを、切り替わった IP を周囲に通知するために arping コマンドを使用します。これらのコマンドのパスやオプションは以下のパラメータで指定することができますが、通常はデフォルトから変更する必要はありません。

ifconfig_path = '/sbin'
                                    # ifconfig command path
if_up_cmd = 'ifconfig eth0:0 inet $_IP_$ netmask 255.255.255.0'
                                    # startup delegate IP command
if_down_cmd = 'ifconfig eth0:0 down'
                                    # shutdown delegate IP command

arping_path = '/usr/sbin'           # arping command path

arping_cmd = 'arping -U $_IP_$ -w 1'
                                    # arping command

何度か述べているとおり、これらのコマンド実行のため watchdog は root 権限で起動される必要があります。root ユーザによる直接実行でも、sudo コマンドを用いても問題はありません。しかし、pgpool-II の GUI 管理ツールである pgpoolAdmin を用いる場合、これらの方法は使えません。pgpoolAdmin は Web アプリケーションなので、apache ユーザで watchdog を起動する方法が必要になります。

1つの方法は apache の実行ユーザとグループを root に変更することです。実行ユーザは httpd.conf の User, Group ディレクティブで設定することが出来ます。(ただし、この場合は apache の再コンパイルが求められます。)もう1つは以下のように pgpool コマンドの setuid フラグを立てる方法です。これらの方法で、apache ユーザ でも pgpool を root 権限で実行することが可能です。

# chown root bin/pgpool
# chmod 4755 bin/pgpool

もう少し安全なものとして pgpool コマンドそのものではなく、ifconfig, arping コマンドの setuid フラグを立てておく方法があります。

# chmod 4755 /sbin/ifconfig
# chmod 4755 /sbin/arping

この方法では pgpool 起動時にログに以下の警告が出力されますが、比較的安全に一般ユーザから watchdog を使用することが可能です *6)

pid 15677: watchdog might call network commands which using sticky bit.
*6) ipconfig, arping に直接 setuid フラグを立てるのは抵抗があるので、将来的には wrapper プログラムを提供する予定です。

(2012 年 9 月 3 日掲載)