最近、弊社でもいくつかのサービスでStarmanが動き始めてます。リソース監視厨としてStarmanやStarletといったPreforkなPlackサーバにおいてもApacheのmod_status同様、使用されているプロセス数、アイドル中のプロセス数を当然知りたいわけです。CloudForecastでグラフにしたいわけです。
すでにcho45氏がその機能を実現しています。cho45++です。ただ、ステータス表示を行うMiddlewareの他にステータス情報の変更を行うためにStarmanやStarletの本体に手を入れており、若干使いにくいという印象を持っていました。そこでMiddlewareだけで、Middlewareのできる範囲でステータスを変更・表示するPlack::Middleware::ServerStatus::Liteを書いてみました。ソースコードはgithubにpushしてあります。
http://github.com/kazeburo/Plack-Middleware-ServerStatus-Lite
仕組みは簡単です。cho45氏の実装をまねて $0 ($PROGRAM_NAME)を変更し、それをpsコマンド経由で収集し、表示します。
$0を変更する実装は以下の様な感じ
sub call {
my ($self, $env) = @_;
$0 = sprintf("server-status-lite[%s] %s",getppid, "A"); #Active
$res = $self->app->($env);
$0 = sprintf("server-status-lite[%s] %s",getppid, "_"); #Idle
return $res;
}
このようにappを実行する前後でステータスをActive(Busy) or Idleで変更しているだけです。Apacheのmod_statusやcho45氏のhackではリクエストの読み込み、書き込み、KeepAliveなどの様々なステータスがとれるのに対してServerStatus::Liteでは2種類の状態しかとることができません。ただ、実際のStarmanやStarletのProduction環境では、リバースプロキシーを全面に設置するため読み込み、買い込みは十分に早くでき、またKeepAliveは無効にしていると思われるので、この簡単なステータスでも十分に焼くに立つのではないかと予想しています。
このように書き換えたステータスをpsコマンドの結果から収集して、Active(Busy)のプロセス数、Idleのプロセス数を数えます。必要なプロセスをすべて調査するために「親プロセスのPIDが同じ」であるプロセスを探しています。
以下は実際にStarlet(max-process=10)でアプリケーションを起動してabでアクセスしている状態のpsの結果(一部)
PPID PID COMMAND
20337 1022 \_ /bin/zsh
1022 20582 | \_ /usr/bin/perl /usr/local/bin/plackup -r -Ilib -p 5003 -s Starlet -a nonopaste.psgi
20582 20583 | \_ /usr/bin/perl /usr/local/bin/plackup -r -Ilib -p 5003 -s Starlet -a nonopaste.psgi
20583 20803 | \_ server-status-lite[20583] _ 127.0.0.1 localhost:5003 GET / HTTP/1.0
20583 20804 | \_ server-status-lite[20583] A 127.0.0.1 localhost:5003 GET / HTTP/1.0
20583 20806 | \_ server-status-lite[20583] _ 127.0.0.1 localhost:5003 GET / HTTP/1.0
20583 20808 | \_ server-status-lite[20583] _ 127.0.0.1 localhost:5003 GET / HTTP/1.0
20583 21153 | \_ server-status-lite[20583] _ 127.0.0.1 localhost:5003 GET / HTTP/1.0
20583 21156 | \_ server-status-lite[20583] _ 127.0.0.1 localhost:5003 GET / HTTP/1.0
20583 21158 | \_ server-status-lite[20583] _ 127.0.0.1 localhost:5003 GET / HTTP/1.0
20583 21163 | \_ server-status-lite[20583] _ 127.0.0.1 localhost:5003 GET / HTTP/1.0
20583 21165 | \_ server-status-lite[20583] A 127.0.0.1 localhost:5003 GET / HTTP/1.0
20583 21168 | \_ /usr/bin/perl /usr/local/bin/plackup -r -Ilib -p 5003 -s Starlet -a nonopaste.psgi
最も左側の項目が親プロセスのPIDで、ここが20583になっているプロセスがPreforkされているプロセスです。6行目と13行目のプロセスが動いているプロセス。一番下のプロセスはまだ一度もアクセスを処理していないので、元のプログラム名のままとなっています。このようなプロセスはIdleのプロセスとカウントしています
このステータス情報はApacheのmod_status同様http経由で取得可能です。おしゃれなHTMLに整形されていたりしませんが以下のように取得可能です
% curl -v http://localhost:5003/server-status
(略)
< HTTP/1.0 200 OK
< Date: Thu, 01 Jul 2010 15:38:49 GMT
< Server: Plack::Handler::Starlet
< Content-Type: text/plain
< Content-Length: 30
<
BusyWorkers: 3
IdleWorkers: 7
このMiddlewareを有効にするには、Plack::Builderを利用して
builder {
enable "Plack::Middleware::ServerStatus::Lite",
path => '/server-status',
allow => [ '127.0.0.1', '192.168.0.0/16' ];
$app;
};
のように設定します。pathはhttpで取得するする場合のURI。allowはアクセス制御用。何も書かないと一切アクセスできません。
このMiddlewareは新サービスで使ってもらえる予定で、リソース監視も当然行う予定になっています。あとはpsgi.multiprocessのflagぐらいは確認した方がいいかなぁと思っています。 ただpsgi.multiprocessがTRUEなmod_perl1で動かすとどうやらセグフォルするようですが。