T

pgpool-IIのオンラインリカバリではrsyncに要注意

pgpool-IIでレプリケーションをしていて縮退運転に入ったとき、オンラインリカバリを実行してrsyncでデータディレクトリを転送するときにちょっとしたコツがいる。

最近、どうもリカバリーに失敗したりすぐに縮退運転に入ってしまうので困っていたのだが、原因はどうも継承を利用しているテーブルにあることがわかった。PostgreSQLの継承はとても便利な機能で、例えばデータがたまる一方のログ用テーブルなどを、日付などで分けて親テーブルを継承した別テーブルに入れてしまうことができて、しかもデータの検索は親テーブルにクエリを投げるだけで実現できるのだが、バッチ処理で作成していた継承テーブルの親子関係がリカバリを実行すると壊れてしまうのだ。

原因は、rsyncされるPostgreSQLのデータ領域の継承関係のデータが格納されているファイルはレプリケーションされた二つのサーバの両方で最終更新日時とファイルサイズが同じで中身だけ違うので、転送を「rsync -avz」などで実行してもリモートサーバ側では更新の対象にならず、スルーされていたからだ。rsyncにはchecksumを利用する「c」オプションがあるので、そちらを利用しないと継承関係のデータが転送されず、結果として上のようなことになる。

pgpool-IIがSERIALに対応

したとのこと

PostgreSQLがボトルネックになるサービスで負荷分散を組み込んだり、冗長性を要求される場合にレプリケーション用にpgpoolを利用したいケースはたくさんあるだろうが、これまで特にレプリケーションではみんな結構苦労していたと思う。

pgpoolのバックエンドサーバのミスマッチはSELECT時にどこかのテーブルの行数の違いを検出するもので、内容については関与していない。SERIALを指定したカラム(MySQLでいうとauto_incrementが指定されたカラム)の不整合が発生しても検知されないので、ここをキーとして構築されたサービスは大打撃となってしまう。

これまでざっとテストした限りではINSERT LOCKを有効にすればSERIALの不整合は防げるようなのだが、INSERT処理が複数のサーバで完了するまで待ちになってしまう(という理解でいいのかな?)ため負荷がシビアな環境ではそのオーバーヘッドを考えると躊躇せざるを得なかった。これでようやくこの問題ともおさらばできるかもしれない。

pgpool-IIのオンラインリカバリ機能と格闘中

いろいろ気づいたことのメモ。

まずは目玉機能のオンラインリカバリについて。プロジェクトのページによれば

1. CHECKPOINT 実行
2. ファーストステージの実施
3. 接続がすべて切断されるまで待機
4. CHECKPOINT 実行
5. セカンドステージの実施
6. postmaster の起動(pgpool_remote_start の実行)
7. ノードの復帰

という手順でリカバリされるのだが、手元の環境でまず引っかかったのが3の「接続がすべて切断されるまで待機」のところ。というのも、pgpool-IIにpgpoolを経由して接続するという変な環境だったのだが、child_life_timeを0に設定していたために接続がいつまで経っても切れずにここで失敗してしまったのだ。

で、pgpool-IIのソース(現時点でrev.1.21)を調べると(これは会社の同僚がやっていた)、まだ接続が切れていなければ3秒待ってから最大30回ループすることになっている。

/*
 * Wait all connections are closed.
 */
static int wait_connection_closed(void)
{
	int i = 0;

	do {

		if (Req_info->conn_counter == 0)
			return 0;

		if (WAIT_RETRY_COUNT != 0)
			sleep(3);
	} while (i++ < WAIT_RETRY_COUNT);

	pool_error("wait_connection_closed: existing connections did not close in %d sec.", pool_config->recovery_timeout);
	return 1;
}

なぜかしびれた。これはプログラム内に意味深な数字を見つけたときのプログラマの健康な反応なのだろう。まあ、根拠はよくわからないが、まあそういう数字であると。ふむふむ。

で、接続元がpgpoolだとコネクションを張りっぱなしになるのでこのループで終了してしまう。負荷の高いサービスだと、pgpool経由でpgpoolにつないだ状態では、child_life_timeを下げてもなかなかチャンスがこないかもしれない。というわけで現在ここを試験中。

接続の問題が解消されると、あっさり動作した。PostgreSQLは7系なのでrsyncで動作している。

PostgreSQLカンファレンス2008

というわけで六本木一丁目まで出かけた。

pgpoolのセッションは大盛況。PostgreSQLである程度の規模のシステムを構築するのにはみんな苦労しているという現実を思い知らされる。内容は、これまで何度か見てきたpgpoolの説明とほとんど変わらなかったが、HeartBeatを利用してpgpoolのところを冗長化する構成が出ていたのがこれまでになかったところ。でもその話題はあまり盛り上がっていなかった。

大規模システムを構築する場合は、パラレルクエリを利用するのはあまりよろしくないな。1個のクラスタが壊れたらどうやって復旧していいのかわからないし、そこをさらにpgpoolで冗長化するのも冗談みたいになって手間がかかってしまう。やはりpgpoolによる同期処理とロードバランシングか、あるいはpgpoolのロードバランシングとSlony-Iによる非同期処理の組み合わせになるだろうか。ただ、後者だと更新系クエリの結果を受けてSELECTを発行しているようなありがちな箇所を変更するなど既存のアプリケーションに手を入れるところが多そうなので、やはりpgpoolで全てまかなえるようになるのが理想的だ。

とはいえ、pgpoolのプロセスそのものを冗長化してSingle point of failureをなくすためにはもっと工夫しないといけない。pgpool自体は同じ設定であちこちに立ててあげれば使えるのだが、ウェブアプリケーション側から接続先を動的に切り替えるのは無理があるので、やはりHeartBeatで監視してアプリケーション側からは接続先の切り替えは見えないようにしてあげるのがいいと思われる。

PostGIS
は前々から興味津々だったのだが、デモが見にくくてこまった。それから、Functionとして利用する機能の説明が駆け足すぎてきちんと把握できず、聴衆がみんな置いてけぼりだったのが難点か。PostGISの単なる紹介なのか、導入事例の紹介なのか、もうちょっと焦点を絞ってあればよかったかも。個人的には面白かったのだが。

全文検索機能については会場の雰囲気からも高い関心がもたれているのが感じられた。しかし、tsearch2(や日本語を扱えるtsearch2の拡張)の実装には関わっていない上にテキスト検索に詳しいわけでもない人がざっと概要を説明するだけのもので、これじゃやっぱ使えないな、という失望感が会場に広がっていた。実際、全文検索はもはや形態素解析かN-Gramかという次元のようなものではなくて、利用局面に応じてどんな順位付けをするのか(できるのか)、どんな実装ができるのかといったもう少しデータ寄りに踏み込んだ内容が求められているはずだ。そのあたりは、LudiaRASTHyper Estraierのような実装の方が相当先に進んでしまっていて、正直なところ今更な感じ。

PGClusterのセッションも、pgpoolと同様に高い関心を集めているようだった。とはいえ、作者の海外赴任にともない活動拠点がヨーロッパになったこと、管理機能を含めまだ未完成の部分があること、身近な導入実績のなさから今では完全にpgpoolに立ち遅れてしまっている感は否めない。だが、PostgreSQLの負荷分散だけでなくoidやLargeObject、Serial値、乱数、時間関数の結果まで同期してしまうという高機能さと、徹底してSingle point of failureをなくそうという姿勢には、従来から高い期待を寄せられていたのも事実だ。これはメインの開発者の気質にもよるのだろうが、実際的な利用を想定してとにかくリリースしてしまうより、実装や構成についてもっと深く突き詰めようとして完成に至らず、実際に利用されるよりも学究的なプロジェクトの様相を呈しているのも残念だ。しかし、開発自体は進んでおり、また開発者も非常に高い理想を掲げているため、今後大きな成果をあげることもあるかもしれない。まあ、カンファレンスの段階であれば、実運用されている環境への導入には躊躇せざるをえないが。

Leopard雑感

Leopardにして困ったこと。

Apache

 apachectlの「ULIMIT_MAX_FILES=”ulimit -S -n `ulimit -H -n`”」の行でエラー。ulimitの引数が「unlimited」になるとエラーらしい。とりあえず動くし手元のテスト環境なので無視。

pgpool-II

 起動したら「could not create shared memory segment: Cannot allocate memory」で死ぬ。どうにもわからんのでpgpoolに戻した。

PHP

 PHP-5.2.5はiconv関連のエラーでビルドできない。ext/iconv/iconv.cを開いて:%s/iconv_open/libiconv_open/gと:%s/iconv_close/libiconv_close/gすればビルドできるようになる。Leopard対応できてない。

kinput2-macim

 Leopard対応していない、と怒られてインストールできない。対策なし。