« Q4M (Queue for MySQL) 0.3 リリース | メイン | Q4M Version 0.4 で高速なクローラを書いてみた »
2008年04月04日
Parallel::Prefork - Perl でマルチプロセスなサーバを書く方法
Perl でマルチプロセス処理を行う場合は Parallel::ForkManager を使うというのが定番かと思います。しかし、このモジュールはシグナル処理を前提とした作りになっていない注1ため、シグナルを受信するまで動き続けるようなサーバを書きづらい、という問題がありました。
そこで、Parallel::ForkManager の API は、ほぼそのままに、シグナル処理が可能なプロセス管理モジュールを作ることにしました。それが Parallel::Prefork です。Parallel::Prefork を使うことで、Graceful Shutdown や動的再構成に対応したマルチプロセス型のサーバを簡単に書くことができるようになります。
たとえば、Apache の prefork MPM のようなサーバは、以下のように書くことができます。
use IO::Socket::INET; use Parallel::Prefork; sub MaxRequestsPerChild () { 100 } my $listen_sock = IO::Socket::INET->new( Listen => 5, LocalAddr => '0.0.0.0:80' Proto => 'tcp', ) or die $!; my $pm = Parallel::Prefork->new({ max_workers => 10, # ワーカープロセスの個数 trap_signals => { TERM => 'TERM', # SIGTERM を受信したらワーカープロセスを SIGTERM HUP => 'TERM', # SIGHUP の場合も同様 }); # メインループ while ($pm->signal_received ne 'TERM') { load_config(); # 設定を読み込み $pm->start and next; # ワーカープロセス生成処理 my $reqs_before_exit = MaxRequestsPerChild; # ここからワーカープロセス内 $SIG{TERM} = sub { $reqs_before_exit = 0 }; while ($reqs_before_exit-- > 0) { my $s = $listen_sock->accept(); # リクエストを処理 ... } $pm->finish; # ワーカープロセスの終了処理 } $pm->wait_all_children; # 子プロセスを待ち受け
これだけで、以下のような条件を満たしたサーバの完成です。って中身はありませんが。
- SIGTERM を受信したら、接続中の全クライアントの処理が終わったタイミングで終了
- SIGHUP を受信したら、設定を再読み込みして、次のリクエストから適用
また、Q4M のようなメッセージキューと組み合わせてタスクをオフロードしたりする場合等においても便利に使えると思います。興味のある方はお試しいただければと思います。
注: 参考: Perl で並列処理 (using マルチプロセス), perl & EINTR投稿者 kazuho : 2008年04月04日 17:31
トラックバック
このエントリーのトラックバックURL:
http://labs.cybozu.co.jp/cgi-bin/mt-admin/mt-tbp.cgi/1833
コメント
とても便利に使わせて頂いています。
一点、掲示されているサンプルソースにある$pmの定義で、"{"が閉じられていないような気がします。
my $pm = Parallel::Prefork->new({
~snip~
}});
とすればOKでした。
投稿者 tf0054 : 2009年02月22日 03:00