ジョブキューサーバ Gearmand を PHP から使ってみた

もうすぐ子供が生まれます。春菜です。

今やってるプロジェクトで新機能追加を検討していて、Perl で有名な「TheSchwartz のようなジョブキューシステムとか試してみたいなぁ。」 なんて話してたらちょうど弊社 村瀬 が社内 TIPS 会で Gearmand について話してたので使ってみました。

Gearmandって何?

元々は Perl で書かれたジョブキューシステムで、つい最近 C でリライトされたようです。 クライアントライブラリとして CPAN はもちろんのこと、PHP や Python などたくさん用意されていて活発的に活動されているみたいです。(期待大!!)

PHP では PECLPEAR のクライアントライブラリが利用でき、本家サイトでも PHP のサンプルが多く紹介されていてそのまま試す事ができて楽チンです。

インストールと起動

ローカルの Mac にインストール。

libevent が入っていない場合は先にインストールが必要です。 また、libevent のバージョンが古いとダメっぽいので最新にしておきましょう。

サーバ

$ wget http://launchpad.net/gearmand/trunk/0.10/+download/gearmand-0.10.tar.gz
$ tar xzvf gearmand-0.10.tar.gz
$ cd gearman-0.10
$ ./configure --with-libevent-prefix=/opt/local
$ make
$ sudo make install

※ボクのローカルでは基本 MacPorts でパッケージ管理しているので configure 時に libevent-prefix を変更してます。

クライアントライブラリ(今回はPECL版を利用)

$ pecl install gearman-0.6.0

サーバ起動

$ gearmand -d

※ -d はバックグラウンドで起動するオプションです。

使ってみよう

まずは定番の Hello world! とか書こうかと思ったのですが、本家にとっても分かりやすいサンプルがあるのでそのまま使ってみましょう。 本家サイトの ココ にもサンプルがあります。

まずは処理を待ち受ける Worker

<?php
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction("reverse", "my_reverse_function");
while ($worker->work());

function my_reverse_function($job) {
    return strrev($job->workload());
}

& をつけてバックグラウンドで実行して待機

$ php worker.php &

続いて呼び出す側の Client

<?php
$client = new GearmanClient();
$client->addServer();
print $client->do("reverse", "Hello World!");

実行すると Hello World が逆転した文字列が出力されます。

$ php client.php
!dlroW olleH

Worker は ‘my_reverse_function’ という関数を ‘reverse’ というラベルで登録。 Client は do() メソッドでの第一引数にWorkerで登録されたラベルを指定し、第2引数で処理するデータを渡します。

おおまかな実行方法を紹介

Client からの Worker に対する実行方法はおおまかに3種類あります。

do() メソッド

処理結果が返ってくるのを待つ。

doBackground() メソッド

処理結果を待たずに、バックグラウンドで実行させる事ができます。

addTask() メソッド

ループ等で複数 addTask() してから runTasks() メソッドを実行すると並列処理してくれます。 ※並列処理を実現するには同じ Worker を複数立ち上げておく必要があります。

PECL 版のクライアントライブラリでの注意点

Worker 内で処理の途中経過等を Client に通知したりするための sendData() や、Warning を通知する sendWarning() 等の send○○() というメソッドが数多く用意されているようなのですがなぜか Client 側で sendFail() や sendException() の通知を受け取る事ができませんでした。。 ※ボクの環境だけなのか、深く調査しきれていないだけなのか、、ウソだったらごめんなさい;-(

とりあえず同じやり方で sendWaring() の通知を受け取れることを確認しているので最悪エラー系はすべて sendWarning() で処理すればいいのですが・・・

信頼性と安心性を向上させるために

Gearmand はデフォルトでメモリ上にキューを保持するため、大きなデータを扱いまくるとメモリを喰い尽くしたり、万が一クラッシュした際に再起動してしまうとキューデータが消えたりしちゃいます。

でもこの Gearman はぬかりない! オプションでキューの管理を別ストレージとしてlibdrizzle を使って MySQL を利用したり、Memcached を使うことができちゃいます。

また、処理を待ち受ける Worker や Gearmand 自体が落ちっぱなしになるのを防ぐためにdaemontools でプロセス監視しておけばそれなりに信頼性と安定性を維持できそうですね。

まだ、ローカルで軽く触ってみただけなのでアレですが、中々いい手応えを感じました。

カヤックではジョブをキューにつっこんでどうのこうのしたいエンジニアを募集していまーす!