QA@IT

ジョブキュー処理のResqueとDelayed Jobの使い分けの方針などはありますか?

15713 PV

現在、Ruby on Railsから使用するジョブキュー処理についてのGemは、ResqueとDelayed Jobがメジャーかと思います。

Ruby ToolboxのBackground JobsのカテゴリではResqueの方が上位ランクになっていますが、それぞれのGemの用途として、向き不向きなどはあるのでしょうか?

こういうシステム、アプリケーションではこちらの方が合っている、Railsとの親和性、コードの組み込み易さ、導入の簡単さ、RSpecなどでのテストのし易さなど、どのような観点でも良いので、ご意見頂ければと思います。

回答

その2者の比較はResqueを作った動機のところで説明されています。

https://github.com/blog/542-introducing-resque

個人的な視点をあげてみます。

Resqueの良い点

  • ジョブ実行時に毎回forkし、毎回クリーンな状態に戻るので、メモリリークが存在する、あるいはメモリのフラグメンテーションがひどい状態になるコード(RMagickとかRMagickとか)でもあまり不安なくデプロイできる(je使えとかいうツッコミはなしの方向で)
  • 付属のWeb UIが超便利、Sinatraだけどroutes.rbでmount Resque::Server.new, :at => "/resque"すればRailsと同居できる
  • エコシステムができあがっている

Resqueの悪い点

  • 毎回forkするので、細かい処理が大量にくる用途だとfork自体のオーバーヘッドがばかにできない。そこそこ長時間かかるジョブ向き。
  • キューのストレージとしてRedisが必要。Redis使ってないなら、めんどくさい。でも、Redisは超便利だからResqueなくても使うことをおすすめしますけどね!
  • defunktが最近オープンソース活動から離れてるので、メンテがHerokuのhoneに引き継がれたけど、v2が出る出る詐欺級に出てこない。pull requestの消化が追いついてない。

delayed_jobの良い点

  • あまりない。いたって普通。Resqueの悪い点で気に入らないところがあるかどうかが争点。

delayed_jobの悪い点

  • DBに専用テーブル作成が必要。色々考えることが増えます。クラッシュセーフのために永続化はしたいけど、あくまで一過性のものなので、役目を追えたイベントが残るのが邪魔だし、消すにしてもそれはそれで意味のない負荷。
  • メモリリークしてるコードがあれば定期的な再起動が必要。まぁこれはサーバプロセスにも言えることですが、バックグラウンド処理のほうが大きなデータを扱う機会が多いと思うので。

という感じです。

あと、最近だとマルチスレッドで動作するsidekiqが人気出てきてますね。Pumaのバックグラウンド版といったところでしょうか。ついでにこいつも。

sidekiqの良い点

  • Resque互換API
  • プールされたワーカースレッドで並列に動作するので、外部サイトへのAPI呼び出しなど、I/O待ちの比率が大きいような用途で使うのに便利。
  • JRubyならGILがなく、I/Oに限らず完全に並列動作するので、resqueやdelayed_jobならプロセスを大量に立てなければいけないところ、1個のプロセスで動作させられるのでメモリ使用量が少なく経済的。マルチコアもフルに活かせる。というか、JRuby使いたいならsidekiq一択でしょうねたぶん。

sidekiqの悪い点

  • forkするわけではないので、メモリリークやフラグメンテーションによるプロセス肥大化には弱い。monitなどでメモリサイズを監視して一定値を超えたら再起動が必要。
  • スレッドプログラミングに慣れてないと、コネクションプールの扱いなどで多少つまづくかも。
  • 逆に並列に動いてほしくないユースケースというのも結構あるのだけれど、そういう場合の扱いがちょっと面倒臭い。

以上、いろいろあげてみましたが、現時点なら、個人的にはまずResqueをプロセス1個で使うところから取り組まれるのが良いと思います。が、それにしても、どれもセットアップめんどくさいですね。

幸い、Rails 4からはQueue APIが標準になり、ついでにThreadedConsumerという簡単なワーカースレッドが標準でついてきます。

これはどういうことかというと、resqueのようなヘビーデューティな別の機構を導入しなくても、Railsのアプリケーションサーバの内部で簡単に非同期動作させることができるようになるということです。たとえばリクエストをブロックせずにActionMailerでメール送るぐらいのことなら、Rails 4本体だけでできるようになります。

個人的に、これと同じことをRails 3でもできるようにcelluloidなどを使ってバックポートしようかとも思ったのですが、腰が上がらないまま現在に至るという感じです。

Rails 4になると標準APIが導入されるということは、逆に言うと、今どれを選んでも、あとで書き換えが必要になる可能性があるということでもあります。そういう意味で、いまは新規導入には微妙なタイミングではありますね。。。

ちょっと余談が過ぎましたが、そんなところで。

編集 履歴 (0)
  • 回答ありがとうございます。
    直近で使う予定の用途が正に「ActionMailerでメール送るぐらい」のことなので、Rails4のQueue APIが今、欲しいところですが、今回は勧めて頂いたResqueでまずはやってみようと思います。Redisもまだ使った事が無かったので、この機会に一緒に使用感を試してみようと思います。分かり易い回答、ありがとうございました。
    -
  • 毎回forkするボトルネックをどうしても避けたいというのであれば、http://github.com/samgranieri/resque-jobs-per-fork というgemで、1 forkごとに処理するジョブの数を制御できますね。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。