RailsのPostgreSQL上でマルチテナントのジョブキューシステムを独自構築する(翻訳)

概要 原著者の許諾を得て翻訳・公開いたします。 英語記事: How We Built A Multi-Tenant Job Queue System with PostgreSQL & Ruby 原文公開日: 2018/01/24 著者: Huy Nguyen サイト: Holistics Blog RailsのPostgreSQL上でマルチテナントのジョブキューシステムを独自構築する(翻訳) 長期間運用されるプロセス(画像のリサイズ、レジュメのスキャン、負荷分析など)を必要とするWebアプリでは、バックグラウンドジョブキューシステムが重要になります。RabbitMQ(メッセージキュー)、Celery、ActiveMQ、Sidekiqなどのソリューションはよく設計されていて、業界でかなり人気を集めています。 本記事では、Ruby/Rails + Postgresを用いて弊社のB2B SaaSアプリ向けのマルチテナントジョブキューを設計/構築する方法をご紹介いたします。ここでは高度な問題についてその理由や解決のために行ったことを解説するとともに、理解を助けるためにいくつか特定のコードを見ていくことにします。 背景と要件 Holistics.ioはSQLベースのBIプラットフォームであり、データチームがエンドユーザー向けにレポートを自動ビルドする機能やダッシュボードの提供を支援します。小規模なスタートアップからテック業界の未上場企業/新規上場企業に至るさまざまなお客様にご利用いただいています。 バックエンドスタック構成: RubyとRails(PostgreSQLデータベース使用) haproxy、nginx、Unicorn Sidekiq(およびRedis): バックグラウンドジョブエンジンとして しくみ: このプラットフォームで誰かがリクエストを送信するとSQLクエリが生成され、顧客のデータベースに送信され、結果を待ち、それを元にチャートが生成されます。 分析用SQLクエリの実行には時間がかかる(数秒から数分)ため、同期的なWebリクエストを使うのはよくありません。このため、リクエストを扱うバックグラウンドジョブキューシステムが必要になります。 弊社の場合、ジョブキューへの要件は次のようになります。 ジョブの情報を永続化すること: バックグラウンドジョブごとに基本的な統計情報(ステータス、実行時間、開始時間、終了時間、結果レコード数など)をトラッキングする必要があります。 マルチテナントであること: 顧客ごとの独自ジョブキューは互いに影響を及ぼしてはならず、ジョブキューごとにサイズを変更可能であること(顧客Aは5つのスロットでコンカレントジョブを5つ実行でき、顧客Bは3つのスロットで3つのコンカレントスロットを実行できるなど) 信頼性: 顧客が必要とする分析はジョブキューに依存するため、ジョブキューは高い信頼性で実行できる必要があります。ジョブはキューに送信した順序で取り出されなければならず、かつ散発的に発生するエラー(ネットワークの問題など)を防ぐためにリトライメカニズムも必要です。 PostgreSQLでマルチテナントジョブキューを構築する 数回の開発を繰り返した後、Rails/RubyとPostgreSQLで構築されたジョブキューシステムが稼働しています。このシステムは、ジョブを管理したり、処理されるキューからジョブをピックアップしたりします。ピックアップされたジョブは、実際にバックグラウンド実行を担当するSidekiqに渡されます。 リクエストのワークフローは次のような感じになります。 ユーザーがWebサーバーにリクエストを送信すると、Webサーバーは新規ジョブを作成してジョブキューエンジンにプッシュし、ジョブIDをクライアントに返す。 ジョブキューエンジンは次に処理するジョブをピックアップし、Sidekiqにプッシュする。 Sidekiqはジョブをピックアップして実行し、結果をキャッシュに書き込んでjobsテーブル内のジョブステータスを更新する。 クライアントはsuccessかerrorのいずれかになるまでWebサーバーにジョブのステータス問い合わせを繰り返す。successの場合はキャッシュから結果を取り出してクライアントに返す。 別のジョブキューを立てる理由とPostgreSQLを使う理由 PostgreSQL上に別のジョブキューシステムを実装することに頑張るのは「車輪の再発明」ではないかといぶかる方もいらっしゃるかもしれません。その主な理由(そして弊社のproductionデータベースであるPostgreSQLを使う理由)は次のとおりです。 … Continue reading RailsのPostgreSQL上でマルチテナントのジョブキューシステムを独自構築する(翻訳)