FrontPage  Index  Search  Changes  RSS  Login

[BackgroundJob][Ruby] Resque とは

概要

Resque は GitHub で開発/運用している、バックグラウンドジョブを作り・複数のキューに配置し・それらを後で処理するための、裏に Redis を採用したライブラリ。

Resque is a Redis-backed library for creating background jobs, placing those jobs on multiple queues, and processing them later.

GitHub のブログ記事から、Resque の背景をメモ。

バックグランドジョブは、perform に応答できる Ruby のクラスかモジュール。 これまで 10m (10 million?) のジョブを処理してきたとの事。

GitHub で他のバックグラウンドライブラリではない理由

  • GitHub では、これまで多くのバックグラウンドジョブシステムを利用してきた
    • SQS
    • Starling
    • ActiveMessaging
    • BackgroundJob
    • DelayedJob
    • beanstalkd
  • この変遷は、これらのシステムを稼働させる中で、システムが持つ制約に対応させる必要があった事や、制約によって考えが変わっていった事が理由

SQS

  • SQS の制約は遅延
  • push と pop との間で数分のタイムラグが発生しうるという噂があった
    • Amazon フォーラム

ActiveMessaging

  • SQS の次に少しの間だけ利用していた
  • GitHub のジョブは Ruby のクラスやオブジェクト
    • Ruby 自身か最小のライブラリである事が重要
  • しかしながら、フレームワークの設計上の都合で断念

BackgroundJob (以降 bj)

  • bj は Ruby や Rails のジョブをバックグラウンドで処理できる
    • 完璧な折衷案
  • ジョブの優先度を指定する事ができる
  • しかしながら、bj は各ジョブで Rails environment をロードする
    • 非常に無駄が多く、単位時間あたりに処理可能なジョブが少ない

DelayedJob (以降 dj)

  • 機能面では bj とほぼ同等
  • ワーカーが永続的であるため、起動時にのみ Rails environment をロードする
  • ジョブは Ruby オブジェクトを YAML でマーシャルしたも
  • ジョブの中でメソッドを遅延実行させる事もできる
  • 完璧
    • いくつかの機能を追加したりもしたが、それらは dj にコミットしているらしい
    • 実際、いくつかの要求が持ち上がるまでの数ヶ月、上手く運用できていた
  • dj は小さなデータベースにおいては非常に優れている
  • しかし、大きくなりすぎると問題が起きる
  • 負荷が大きくなったり、キューのバックアップを実行したりすると、クエリ処理は非常に高価になる
    • ジョブの作成に 2 秒以上かかったり、ロックによってそれ以上の時間を必要としたりする事もある

beanstalkd

  • 解決のために beanstalkd に移行した
  • 高速・複数キュー・優先度・YAML での通信
  • 裏にデータベースを必要とするシステムと異なり、非常にコンスタントにキューの push/pop 操作を行える
  • 実験的に永続性も実現していた
  • しかしながら、いくつかの dj の特徴は失ってしまった
    • 失敗したジョブを確認する
    • ペンディング中のジョブを確認する
    • キューの操作
  • 裏にデータベースを必要とするシステムは、多くの魅力的な機能を提供してくれる
    • そこで dj に戻った

dj (2 回目)

  • ワーカーがはまったか数時間処理中である場合に
    • dj は、ジョブ待ちのワーカーがいるなら、そのワーカーのロックを解除し再実行する機能を持っている
  • しかしながら、そういう場合は中断か失敗としたい場合もある
    • コードを追加して対応した
      • ジョブをタイムアウトで失敗とし、他のワーカーがそのジョブを永続的な失敗としてからワーカーのロックを解除する
    • 全てのワーカーが、自分以外のワーカーの面倒を見る仕組み
  • 全てのワーカーがはまるか長時間実行中となるかしたらどうなるか
  • ワーカーを管理するマネージャーが必要
    • ワーカーの監視と終了のために monitgod を好む人たちがいる
    • 長時間稼働してメモリを大量に使用しているワーカーを web フロントエンドなどから終了させられる必要がある
  • god でワーカーを監視し、古かったり膨張したワーカーを終了させるようにした
    • ウェブフロントエンドで色々な操作を行える必要があり、そのシステムを各サーバで稼働させるのは面倒
      • キューの状況
      • ペンディング中のジョブ
      • いくつのワーカーが実行中か
    • 数秒かかる起動時間も問題
  • キューに何が起きているか見たい
  • 失敗したジョブを知りたい
  • 状態を知りたい
    • ワーカーの稼働時間
    • ワーカーが処理したジョブの数
    • 処理したジョブの総数
    • どれだけのエラーが発生しているか
  • 50% がバックグラウンド処理でなければ、DelayedJob を勧めるが、GitHub は 50% がバックグラウンド処理

解決策の模索

  • 以前の GitHub のアーキテクチャは、バックグランドジョブを処理するための専用スライスを一つ持っていた
    • dj ワーカーを 25 個走らせてジョブを実行していた
    • "utility" スライス
  • 新しい GitHub のアーキテクチャでは、特定のジョブを特定のマシン上で実行する必要がある
    • GitHub のデータ分散と高可用性において、単一の utility スライスでは十分でない
  • bj と beanstalkd では、名前付きキューや "tags" をサポートしているが、dj ではサポートしていない
    • 「このジョブは X というタグがつけられ、X というタグがつけられたジョブのみに興味を持つワーカーが実行する」
      • 例えば、ダウンロード用に tarball 化や zip 圧縮を行う "archive" ジョブを考える
      • このジョブは、ダウンロードするファイルを提供するサーバ上で実行する必要がある
      • "archive" ジョブに "file-serve" タグをつけ、ファイル提供用スライスでのみ実行させる
    • この機能を dj に追加したが、GitHub のバックグラウンドジョブのシチュエーションを再評価するきっかけとなった
  • このまま、GitHub で必要とする機能を dj に追加し続ける事が妥当な事なのか
  • GitHub が必要とする事を一覧にした
    • 永続性
    • ペンディング中のジョブを確認する
    • ペンティング中のジョブを適切に変更する
    • タグ
    • 優先度
    • 高速な push/pop
    • どのワーカーが実行中か確認する
    • どのワーカーが完了したか確認する
    • 失敗したジョブを確認する
    • 肥えたワーカーを終了させる
    • 古くなったワーカーを終了させる
    • 実行時間が長過ぎるワーカーを終了させる
    • ロード済みの Rails を保持する (永続的なワーカー)
    • ワーカーの割当 (複数のマシンで動かす)
    • 複数のタグに対応できるワーカー
    • 失敗したジョブを再実行しない
    • 失敗したジョブを解放しない

Redis

  • 以下の特徴を備えたシステムの名前がわかるだろうか
    • アトミックに、O(1) で push/pos できる
    • mutating なしでリストをページネートできる
    • 高速
    • 依存関係なしに簡単にインストールできる
    • 信頼できる Ruby クライアントライブラリ
    • 任意の文字列を格納できる
    • 整数カウンタをサポートする
    • 永続性
    • マスタ/スレーブのレプリケーション
    • ネットワーク
  • つまり Redis
  • キューの問題を Redis に任せ、ワーカーの問題に焦点を当てる
    • 可視性、信頼性、状態監視
  • そこで Resque
    • ワーカーを監視するウェブインターフェース
    • 応答のための親子 fork モデル
    • 交換能な失敗したバックエンド
    • 他にも Redis の能力
Last modified:2009/11/08 18:48:53
Keyword(s):[ruby] [backgroundjob]
References: