Sidekiqのキュー詰まりを改善する優先順位
「メール送信が数時間届かない」「CSVエクスポートが終わらないとサポートに問い合わせが来る」「Sidekiqの管理画面を開いたらキューに数万件溜まっていた」——事業が伸びてきたタイミングで、こういう相談が急に増えます。サービス開始当初は数秒で終わっていた非同期ジョブが、いつの間にか処理待ちの山になり、ユーザー体験を静かに悪化させている、という状態です。この記事では、Sidekiq(や類似の非同期ジョブキュー)の詰まりがなぜ起きるのかを整理し、改善の優先順位と外注時の進め方を解説します。
なぜ「見えないところ」から壊れていくのか
Webアプリの同期的なレスポンスが遅ければ、ユーザーはすぐに気づきますし、開発チームもすぐ対応します。一方、非同期ジョブは「裏側で後から処理される」前提のため、遅延が発生しても画面には何も表示されません。気づいたときには、キューに数万件のジョブが溜まり、本来数秒で届くはずのメールが数時間遅れている、という状態になっています。
さらに厄介なのは、非同期ジョブの遅延は事業成長と表裏一体で悪化する点です。会員数が増えれば通知メールが増え、注文が増えればレシート生成や外部API連携のジョブが増えます。設計時には想定していなかった量のジョブが同じキューに流れ込み、当初は問題にならなかった処理順序や並列度の設計が、そのまま詰まりの原因になります。「機能追加は続けているのに、キューの設計は最初のまま」というギャップが、遅延と失敗の温床です。
よくある原因を切り分ける
「キューが詰まっている」という症状は同じでも、原因は複数あり、対策がまったく異なります。まず切り分けが必要です。
- 全ジョブが同じキューに入っている: 数秒で終わる軽い通知ジョブと、数分かかる重いレポート生成ジョブが同じキューを取り合い、軽いジョブまで待たされる
- 並列度(worker数・concurrency)が実際の負荷に対して少なすぎる: サーバー増強やスケールを一切見直さないまま運用を続けている
- 一部のジョブが極端に重い: N+1クエリや、外部APIへの同期的な呼び出しがジョブ内に埋め込まれていて、1件の処理に数十秒かかっている
- リトライが「嵐」を起こしている: 外部APIの一時障害やDBの接続切れで失敗したジョブが、デフォルトのリトライ設定(Sidekiqなら最大25回、指数バックオフ)で何度も再試行され、その間に新規ジョブも積み上がって収拾がつかなくなる
- DB側がボトルネックになっている: ジョブ自体は速くても、大量のジョブが同時に同じテーブルへ書き込み・ロックを取り合い、DB側の詰まりがジョブの詰まりとして観測される
このどれに当てはまるかで打ち手が変わるため、Sidekiqの管理画面(またはダッシュボード)でキューごとの待機件数・処理時間・失敗率を計測するところから始めます。感覚で「並列度を上げよう」と手を打つと、DBがボトルネックのケースではむしろ悪化することもあります。
改善の優先順位
診断結果に基づいて、私たちは概ね次の順序で改善します。
1. キューを重要度・処理時間で分割する
「決済確認メール」のような即時性が求められるジョブと、「月次レポート生成」のような数分かかっても問題ないジョブを、別々のキューに分離します。Sidekiqであれば queue: オプションと -q high,4 -q default,2 -q low,1 のような重み付けで、重要なジョブが軽いジョブに埋もれない構成を作れます。これだけでユーザーが直接影響を受ける遅延の多くが解消するケースが多いです。
2. 並列度をボトルネックに合わせて調整する
worker数・concurrencyを上げる前に、DBのコネクションプールが耐えられるかを必ず確認します。concurrency を上げてもDBの pool サイズが足りなければ、ジョブがDB接続待ちでブロックされるだけで、実質的なスループットは変わりません。ここはRailsアプリ側の database.yml とSidekiq側の設定をセットで見る必要があります。
3. 重いジョブを分解・非同期化し直す
1件のジョブの中でN+1クエリが起きている、外部APIを同期的に何度も叩いている、といったケースでは、キューをいくら分割しても根本解決になりません。バッチクエリへの書き換えや、外部APIへのリクエストをさらに細かいジョブへ分割する、といったジョブ自体のリファクタリングが必要です。
4. 冪等性を確保してからリトライ設計を見直す
ジョブが「同じ入力で2回実行されても安全」(冪等)になっていないと、リトライのたびに二重送信・二重課金のリスクが生まれます。冪等性を確保した上で、リトライ回数の上限・バックオフ間隔・デッドレターキュー(何度も失敗したジョブを隔離して人間が確認する仕組み)を設計し直します。ここを先にやらずにリトライを強めると、障害時に「嵐」がさらに悪化します。
5. 監視とアラートを入れる
キュー詰まりの多くは「本当は数日前から兆候があったのに誰も気づかなかった」ケースです。キューの待機件数・処理時間・失敗率にしきい値を設定し、Slack等へアラートを飛ばす仕組みを入れることで、詰まりが顧客に影響する前に対応できるようになります。既存プロダクトの改善では、コードを直すのと同じくらい、この「気づける状態を作る」ことが再発防止に効きます。
外注時の進め方
非同期ジョブの改善を外部チームに依頼する場合、いきなり「並列度を上げてください」という発注ではなく、まず現状の計測から始められる体制かを確認するのがおすすめです。私たちが実際の案件で踏む手順は次の通りです。
- Sidekiqの管理画面・ログ・DBのスロークエリログを1〜2週間分観測し、詰まりの原因を切り分ける
- 影響範囲の大きい(ユーザー体験に直結する)キューから優先順位をつけて改善計画を立てる
- キュー分割・並列度調整など、リスクの低い設定変更から着手し、効果を計測しながら次の手を打つ
- 冪等性の確保やジョブのリファクタリングなど、コード変更を伴う改善は既存の挙動を壊さないよう回帰テストを足しながら進める
- 監視・アラートを整備し、改善後も詰まりの兆候を早期発見できる状態にして引き渡す
原因の切り分けを飛ばして「とりあえずサーバーを増強する」対応は、コストだけかさんで根本解決にならないことが多いです。詰まりの原因診断そのものを含めて依頼できるかどうかを、外注先選びの基準にしてください。
まず自分たちで最低限の状態を確認したい場合は、既存プロダクト改善で最初に見る観点や、隣接するバッチ処理の安定化の記事も参考にしてください。夜間バッチと非同期ジョブは根本原因が共通していることも多く、両方を合わせて棚卸しすると効率的です。
まとめ
- Sidekiqなどのキュー詰まりは、キュー設計・並列度・重いジョブ・リトライ嵐・DB負荷のどれが原因かを切り分けることが最初の一歩
- 改善はキュー分割→並列度調整→ジョブの分解→冪等性確保とリトライ設計→監視導入の順で進めると、リスクを抑えながら効果を出しやすい
- 外注する際は「原因の計測・切り分け」から任せられるチームかどうかが、根本解決になるか対症療法で終わるかの分かれ目
torcheeesでは、Sidekiqをはじめとする非同期ジョブの詰まり・遅延・失敗の診断から改善実装まで、既存プロダクト改善支援(開発診断・改善支援)として承っています。Rails案件での実績を中心に、Ruby on Railsの技術ページや保守・改善サービスもあわせてご覧ください。まずは現状の計測から始めたいという方は、お問い合わせフォームからご相談ください。