Perl Hackers Hub

第10回 ジョブキューで後回し大作戦―TheSchwartz,Qudo,Q4M(1)

この記事を読むのに必要な時間:およそ 2.5 分

GearmanとTheSchwartz

Perlで作られた有名なジョブキューライブラリとしては,GearmanTheSchwartzがあります。両方ともmemcachedの作者Brad Fitzpatrick氏によって書かれたプロダクトです。Perl界隈ではおそらくこの2つが一番使われています。それぞれの特徴を簡単に説明します。

Gearman

Gearmanはgearmandという専用デーモンを立ち上げて利用します。アプリケーションからはgearmandに対してジョブを登録します。gearmandは受け取ったジョブ情報をオンメモリで確保しつつ,登録されているワーカに処理をディスパッチします。ジョブ情報がオンメモリで持たれているため,gearmandを再起動してしまうとジョブが失われます図1⁠。

図1 Gearmanの処理構成

図1 Gearmanの処理構成

TheSchwartz

TheSchwartzはGearmanのような専用デーモンを必要とせず,MySQLなどのRDBMSを利用します。アプリケーションからはTheSchwartz用に定義されたスキーマに対してジョブをINSERTします。登録されたジョブはユーザが作成したワーカプログラムによって取り出され処理されます。Gearmanと大きく異なる点は,ワーカプロセスを再起動しても処理すべきデータはデータベースに保存されているので,ジョブが失われないことです図2⁠。

図2 TheSchwartzの処理構成

図2 TheSchwartzの処理構成

どのように使い分けるか

では,GearmanとTheSchwartzはどのように使い分けるべきなのでしょうか。一般的にはGearmanはジョブ情報がロストしても問題なく,ある程度のリアルタイム性が必要な場合に利用され,TheSchwartzはジョブ情報のロストを守り,ある程度の遅延が許容されるときに利用されます。

たとえばメール送信処理であれば,ジョブがロストされることは許されませんが,送信の遅延はある程度許されるので,TheSchwartz を利用します。逆にGearmanの使いどころの一例はページングの処理などです。ユーザからのアクセスを受け,次のページを先読みしてキャッシュデータを作っておき,ユーザの次のアクセスに備える場合などに使います。先読みでデータを作成する場合,完全なリアルタイム性は必要ありませんが,ユーザの次のアクセスまでにはキャッシュデータができていることが望ましいです。

TheSchwartzの使い方

紙幅の都合で今回はTheSchwartz的なジョブキューの使い方のみを取り上げます。

TheSchwartzを使うにはデータベースが必要です。最新のバージョンではMySQL,SQLite,PostgreSQLに対応しています。ここではMySQLを使った方法を紹介します。

TheSchwartzのディストリビューションにschema.sqlというファイルが同梱されているので,このsqlファイルをお使いのMySQLに流しこんでください。TheSchwartz自体はCPANからインストールできます。

アプリケーションからジョブを登録するには,TheSchwartzのinsertメソッドを利用します。

#! /usr/bin/perl
use strict;
use warnings;
use TheSchwartz;

my $client = TheSchwartz->new(
    databases => $connect_info
);
$client->insert('MyWorker', \%args);

登録したジョブを処理するワーカは次のようになります。

package MyWorker;
use strict;
use warnings;
use parent 'TheSchwartz::Worker';

sub work {
    my ($self, $job) = @_;
    my $arg = $job->arg;
    # ここでワーカにジョブを処理させる
    $job->completed();
}

ワーカクラスはTheSchwartz::Workerクラスを継承したクラスを作成し,workメソッドをオーバーライドして実際に処理したい内容を記述します。workメソッドの第2引数にTheSchwartz::Jobのインスタンスオブジェクトが渡ってきます。TheSchwartz::Jobのargsメソッドを呼び出すことで登録してあるジョブの情報を取り出せます。そして,workメソッド内で行いたい処理が正常に終了したら,TheSchwartz::Jobインスタンスのcompletedメソッドを実行し,ジョブが正常に終了したことを記録します。

上記で作成したワーカを使って実際にジョブを処理させるには,次のようにします。

#! /usr/bin/perl
use strict;
use warnings;
use TheSchwartz;

my $client = TheSchwartz->new(
    databases => $connect_info
);
$client->can_do('MyWorker');
$client->work;

TheSchwartzクラスのworkメソッドを実行することで処理が無限ループに入り,クライアント側からジョブが登録されるのを待ちます。ジョブが登録されたら対応するワーカクラスに処理を振り分けます。

Webアプリケーションなどのクライアント側で行うべき処理は,単純にデータベースにジョブをinsertするだけです。

ただ,TheSchwartz自体はクライアント側の処理とワーカ側の処理を行える作りになっているため,ジョブをinsertするだけにしては若干重い作りになってしまっています。そもそも重い処理を非同期に行うしくみなのにジョブの登録で時間がかかっては本末転倒ということで,宮川達彦氏によってTheSchwartz::Simpleというライブラリが作成されました。TheSchwartz::Simpleを使うと,TheSchwartzをそのまま使うよりも高速にジョブをinsertできるので,より早くユーザにレスポンスを返せます。TheSchwartz::Simpleのインタフェース自体はTheSchwartzと大きく変わらないので,今までTheSchwartzだけ使っていた場合も簡単に置き換えることができます。

著者プロフィール

小林篤(こばやしあつし)

株式会社ディー・エヌ・エー プラットフォームシステムグループに所属。Mobagae APIやGadget Serverを担当。

「YAPC::Asia」や「Yokohama.pm」などでスピーカーをするなど,Perl関連のコミュニティへ積極的に参加している。YAPC::Asia2010ではベストスピーカ賞(次点)受賞。

CPANモジュールに「DBIx::Skinny」「Teng」「Qudo」など多数。

ネコが大好きだが,パグを2頭かってるプログラマ。

Twitter:@nekokak

Blog:http://blog.nekokak.org/