2012年も残すところあと20日ほどとなりましたが皆様いかがお過ごしでしょうか。@fujiwara です。
このエントリは tech.kayac.com Advent Calendar 2012 10日目の記事です。
テーマが「私の中のマイイノベーション 2012」ということで、まずこの1年に作ったものを自分の blog エントリから振り返ってみますと…
- Perl から Fluentd にログ出力 - Fluent::Logger リリース
- 今年一番話題になったミドルウェアといえば fluentd でしょうか。その fluentd に Perl からログを出力するためのモジュールです
- Parallel::Benchmark というモジュールを書きました
- 並列にプロセスを起動して負荷を掛けるベンチマークを簡単に作るためのフレームワークです。弊社の主にソーシャルゲーム案件で、リリース前の負荷テストに重宝しています
- fluent-plugin-zabbix リリース
- fluentd で集計したログを Zabbix に送信するための出力プラグインです。弊社では監視に主に Zabbix を使用しているので、ログの可視化やアラート送信に使っています
- Monitoring Casual Talk #1 で im.kayac.com の話他をしてきました
- 弊社の大変便利な通知サービス im.kayac.com へログを送信するもので、もにかじ#1 に合わせてでっち上げたネタ的プラグインですが、動きます。使っているかたいますかね…
- リクエスト処理前後のメモリ使用量を調べる Plack::Middleware::GTop::ProcMem を書いてみた
- とあるサービスで、メモリリークする処理を特定するために書きました
- 同じメッセージを間引く fluent-plugin-suppress を書いた
- アラートをメール送信すると、飛びすぎるのが困るのです
こう振り返ってみると fluentd 関連が非常に多くて、やはり自分の中でもホットなプロダクトだったのだなと思います……が、ここから先は fluentd は関係なく、kazeburo さんが書かれた Proclet が便利だよーというお話をしたいと思います。
最近、『jobの一時保管 & 再実行機能付き job queue』という不思議なものを Perl で書きました。 Surface - github
メインで利用している Zabbix の監視に対して、外部の別のネットワークから Zabbix Server やそれが配置されているネットワークが落ちていないかを監視するための、サブシステムを作るために用意したものです。
- 監視項目の定義はメインの Zabbix で一元化したい
- メインのホストが落ちている間も、定期的に外部監視を実行したい
という要件があったため、Zabbix上で定義したアイテムを zabbix-agent 経由で job queue に投入し、job workerが監視を実行。jobの投入が一定時間以上途絶えた場合には、最近投入されたjobを定期的に再実行することで、監視を継続するような仕組みです。
job queue の実装には Redis を用いて、以下のような処理を行っています。
- RPUSH で job を LIST に投入
- BLPOP で worker が job を取得して処理
- Sorted Set で最近投入された job を保管
また、job の投入を curl などで簡単に行うために、Plack を利用した HTTP API も用意しました。
つまり、これらが動作するためには以下の4つのプロセスが同時に動作する必要があります。
- job の再実行を管理する manager
- job を処理して監視を行う worker
- job 投入 HTTP API のための PSGI application
- queue を実装するための Redis
これをいちいち、daemontools やら supervisor などでプロセスを起動するのは面倒ですよね。本番ならまだしも、開発中ならなおさらです。
……ということで、前置きが大変長くなりましたが、Proclet を利用することで、これらの複数プロセスを一つのスクリプトで管理することができて、ものすごく便利なのです!
例: https://github.com/fujiwara/Surface/blob/master/examples/surface_service
Proclet::Declareを使用することで、redisを子プロセスとして起動するのは1行です。
use Proclet::Declare;
service("redis", "redis-server", "redis.conf");
Manager や API プロセスは Perl で動作するので、コードで記述できます。
service(
"api",
sub {
Surface::WebAPI->new(...)->run( "-p" => "9000" );
}
);
worker に同じプロセスを3つ起動したい場合も簡単。
service(
"worker",
sub {
while (my $msg = $surface->dequeue) {
next unless $msg;
infof "worker[%d]: got message %s", $$, ddf $msg;
}
}
);
worker(
worker => 3,
);
各プロセスが標準出力、標準エラー出力に吐き出す内容を、色分けして表示できます。
color;
run;
いやあ、Proclet マジ便利ですね!!
開発中に Redis, memcached などのアプリケーションから利用するミドルウェアを起動したり、外部の Web API を呼び出すアプリケーションを開発するために、ダミーの実装を立ち上げておきたい、などの目的にも使えます。
Plack::Runner を使うと、app.psgi をファイルとして用意しなくても plackup 同様のオプションで起動できて、管理が楽になりますね。
service('dummy_api', sub {
my $app = sub {
[ 200, ["Content-Type", "text/plain"], ['{"success":1}'] ];
};
my $runner = Plack::Runner->new;
$runner->parse_options("-p", 5001);
$runner->run($app);
});
ということで、大変便利な Proclet、おすすめですので是非使ってみてください。
明日は @9renpoto さんのエントリーですのでお楽しみに!