geek.conf.2

あるエンジニアの備忘録

slony-Iでフェールオーバ・・・からのぉぉ・・フェールバックしよっか

こんばんわ、やっぱ人間働かないといろいろとダメっすね、ちっす僕です。
いやぁ世間は無職につめてぇつめてぇうぇっうぇっ

本日はpostgreSQL8.4系をconfigしたマスター/スレーブノード間のDBをslony-I1.2系を使用してレプリケーションして可用性をうまーしよーシリーズ最終章です。pgpool-IIは3系な!各章を以下に。


slony-Iをインストールしよっか

slony-Iでレプリケーションしよっか

pgpool-IIをインストールしよっか、そして設定もしようよ

上記うちpgpool-IIをインストールしよっか、そして設定もしようよレプリケーション中にサーバに障害発生時でも自動で正常サーバに切り替えること→フェールオーバの方法にまつわるetcなの。

平たく言うと、postgreSQLとwebアプリケーションとのプロキシとして振る舞うpgpool-IIにマスター/スレーブノードのヘルスチェックを行わせて、かつ接続先を制御(正常時はマスターノードへ)させて運用し、ノードに障害が発生したらpgpool-IIにあるコマンド(例:home/pgpool2/failover.sh)を実行させて即時に自動でフェールオーバしよーぜって。

で、本エントリーではもしもslony-Iレプリケーション中にノード障害が発生したら?について。

ケース1:スレーブノードの障害
スレーブノードには正常時だれも接続していない(pgpool-IIはヘルスチェックしているよ)ので主な作業としてはレプリケーションの再構築になります。
pgpool-IIが実行する/home/pgpool2/failover.shには本ケースのときはスレーブノードに対して
pg_ctl -D /usr/local/pgsql/data -m immediate stopとslon_killを実行しているのでpostgreSQLslony-Iは停止しているはず。これを起動しますね。

1.スレーブノードのpostgreSQLslony-Iの起動
詳細は割愛、レプリケーションができていることを確認してね。

2.pgpool-II再起動
ここがやっかいですが、pgpool-IIは一度障害と判断したノードが正常に戻っても自動でマスター/スレーブノードにくわえてくれません。故に再起動が必要です。
ちょっとさらに調査進めてここ改善できんか調べるさかい、お待ちください。もしくは情報お持ちでしたらコメントしていただけると助かります。

ケース2:マスターノードの障害
この場合、pgpool-IIは/home/pgpool2/failover.shを実行してマスター/スレーブノードを切替える。postgreSQLも停止している状態にする。
詳細にはpg_ctl -D /usr/local/pgsql/data -m immediate stopとslonik_failover 1 2 | slonik
であーる。

すると障害を起こしたマスターノード(元マスターノードと呼ぶ)はslony-Iからも切り離される。
なのでフェールバックは正常時のマスター/スレーブノードの構成にする必要がある。
さらに最新DBはマスターノードに昇格したスレーブノード(現マスターノードと呼ぶ)が持つのでこれも反映する必要もある。
ちなみにpostgreSQLの状態としては
元マスターノード→postgreSQL停止
現マスターノード→postgreSQL起動中

具体的には元マスターノードを現マスターノードのスレーブノードとして一旦再構築し、その後マスター/スレーブノードの関係を入れ替える。(スイッチオーバ)
※MasNod:マスターノード(元マスターノード)、SlaNod:スレーブノード(現マスターノード)


1.マスター/スレーブノードでslon_kill
[slony1@MasNod etc]$ slon_kill 1
[slony1@SlaNod etc]$ slon_kill 2

2.元マスターノードのpostgreSQLを起動
詳細手順割愛。

3.元マスターノードでDB再作成, createlang, テーブルスキーマ作成を実施
[slony1@MasNod etc]$ drop geekdb
[slony1@MasNod etc]$ create geekdb
[slony1@MasNod etc]$ createlang plpgsql geekdb
↑この行ではplpgsqlというslony-Iで使用する手続き言語を対象DBにインストールしている。
[slony1@SlaNod etc]$ pg_dump -s geekdb | psql -h MasNod geekdb
↑最後の行では現マスターノードのスキーマのみをダンプして元マスターノードにリストアしています。
ちょっと知ってる風テクっす。

4.マスター/スレーブノードのslon_tools.conf内のマスターノード設定値を現マスターノードに変更
[slony1@MasNod etc]$ vi /usr/local/slony1/etc/slon_tools.conf
$MASTERNODE = 1; => $MASTERNODE = 2;
[slony1@SlaNod etc]$ vi /usr/local/slony1/etc/slon_tools.conf
$MASTERNODE = 1; => $MASTERNODE = 2;
slony-Iにマスターノードを入れ替えることを教えるわけですな。

5.slonik_drop_nodeで元マスターノードを削除
[slony1@SlaNod etc]$ slonik_drop_node 1 | slonik
slony-Iに元マスターノード情報を削除せよと命令するわけですな。

6.slonik_store_nodeで元マスターノードにレプリケーションスキーマを再作成
[slony1@SlaNod etc]$ slonik_store_node 1 | slonik
:6: Error: namespace "_replication" already exists in database of node 1
↑上記エラーとなった場合、本エントリー末に記載する対処を行う

7.slonik_drop_setでset1の情報を削除(現マスターノード側が持つset1情報クリアのため)
[slony1@SlaNod etc]$ slonik_drop_set set1 | slonik

8.slonik_create_setでset1の情報を再作成
[slony1@SlaNod etc]$ slonik_create_set set1 | sed s/"public."/"geekdb."/ | slonik
:18: PGRES_FATAL_ERROR select "_replication".determineIdxnameUnique('public.additional_roll', NULL); - ERROR: Slony-I: determineIdxnameUnique(): table "public"."additional_roll" not found
↑上記エラーとなった場合、本エントリー末に記載する対処を行う

9.マスター/スレーブノードでslon_start
[slony1@MasNod etc]$ slon_start 1
[slony1@SlaNod etc]$ slon_start 2

10.slonik_subscribe_setでレプリケーション開始
[slony1@SlaNod etc]$ slonik_subscribe_set set1 1 | slonik
元マスターノードのスレーブを現マスターノードとするよう設定しているんですな。
レプリケーションが正常に動作することをSELECT文で見比べたりして確かめよう!

11.マスター/スレーブノードのslon_tool.conf内のマスターノード設定値を元マスターノードに変更
[slony1@MasNod etc]$ vi /usr/local/slony1/etc/slon_tools.conf
$MASTERNODE = 2; => $MASTERNODE = 1;
[slony1@SlaNod etc]$ vi /usr/local/slony1/etc/slon_tools.conf
$MASTERNODE = 2; => $MASTERNODE = 1;

12.slonik_move_setでマスターノードをスイッチオーバ
[slony1@SlaNod etc]$ slonik_move_set set1 2 1 | slonik
さて本エントリーの胆にようやくたどり着く。slonik_move_set 現マスターノードID 元マスターノードIDでスイッチオーバっす。一度は打ってみたいコマンドslonik_move_set!!ぼく当時打った後ドヤ顔だったと思います。

13.pgpool-II再起動

14.pgpool-IIからpostgreSQLpsqlし、show pool_nodesで元マスターノードがpgpool-IIノードとして稼動していることを確認する

付録.手順6.slonik_store_nodeで元マスターノードにメタデータを再作成および手順8.slonik_create_setでset1の情報を再作成 作業時に発生するエラー対応

これは元マスターノードに対するDB再作成時、現マスターノードからpg_dumpによってスキーマ情報をリストアすると、slonik_store_nodeによって作成されるレプリケーションスキーマが、すでに作成されているために重複して作成できない、という旨のエラーメッセージである。レプリケーションスキーマはプレフィックス_replicationが付くんですな。
スキーマ情報をコピーした後にレプリケーションスキーマを削除することで解消する。

[slony1@MasNod etc]$ psql geekdb -h MasNod -c "drop schema _replication cascade"


最後に.
さて当時はpostgreSQL9が未リリースでストリーミング・レプリケーション(SR)ができなかったためslony-Iレプリケーションツールに採用しました。
僕のケースではこの採用は失敗に終わり、postgreSQL9リリース後にすぐにバージョンアップしてSRに移行しました。24/365システムで開発アプリも受託していたのでバージョンアップにはもろもろ調整含め苦慮しました。

僕のケースでは24/365、利用者数最大3万人のファイル管理システムでした。slony-Iレプリケーションで運用すると表側からでは異常でないのにpgpool-IIに異常と判断されフェールオーバが起こってしまい使い物になりませんでした。

好き勝手に書きますが、決してslony-I構築が悪かったわけと思っていません。開発アプリ言語にJava、その環境にc3poを使用し、開発アプリ内でもコネクションプールによってpostgreSQLとしゃべっていました。もちろんpgpool-IIでもコネクションプールします。この2重のコネクションプールおよびpgpool-IIのヘルスチェックの送受信かつマスター/スレーブノード間のトリガ関数によるslony-Iレプリケーションの相性が悪かったと思います。
postgreSQL純正であるSRにするとこの現象は起こらなくなりました。

僕のpostgreSQL人生の中でもいい勉強になった案件であったため本エントリーを作成しました。
次はpostgreSQL純正のSRについて掘り下げたエントリーで。ほいじゃ!