Skip to content

非同期タスク:Producer/Consumer パターン ​

はじめに

ユーザーが「レポートをエクスポート」ボタンをクリックし、回転するローディングアニメーションを30秒間見つめ続ける——これは妥当でしょうか? 操作が完了するまでに数秒から数分かかる場合、ユーザーを待たせるのは明らかに良い体験ではありません。非同期タスクキューはこの問題を解決する核心的なアーキテクチャパターンです——時間のかかる操作をバックグラウンドに送り、ユーザーに即座に応答を返します。

この記事で学べること

この章を学び終えると、次の能力が身につきます:

  • 同期・非同期の比較:なぜ特定の操作を非同期化しなければならないか、非同期化がもたらすUX向上を理解
  • プロデューサー・コンシューマーモデル:Producer-Consumerパターンの核心思想とワークフローを習得
  • ワーカープール機構:タスクが複数のWorkerに分散されて並列処理される仕組みを理解
  • 信頼性の確保:タスクリトライ、冪等性、デッドレターキューなどの保障機構を習得
  • 技術選定力:主要な非同期タスクフレームワークの特徴と適したシーンを理解
章内容コアコンセプト
第1章なぜ非同期が必要か同期ブロッキング vs 非同期ノンブロッキング
第2章プロデューサー・コンシューマーモデルProducer、Queue、Consumer
第3章ワーカーワークプール並行処理、タスク分散
第4章信頼性の確保リトライ戦略、冪等性、デッドレターキュー
第5章フレームワーク選定Celery、Sidekiq、Bull、RQ

0. 全景図:なぜユーザーを「待たせて」はいけないのか ​

レストランで注文することを想像してください。良いレストランでは、注文が終わるとすぐに番号札を渡してくれ、席を探したりスマホをいじったりして、料理ができたら取りに行きます。カウンターの前に立ってシェフが料理を完成させるのをじっと見ているようなことはしません。

Webアプリケーションには似たような「料理」操作がたくさんあります:

  • メール/ SMS送信:サードパーティAPIの呼び出し、数秒かかる可能性
  • レポート/ PDF生成:大量のデータ計算、数十秒かかる可能性
  • 画像/動画処理:圧縮、トランスコード、ウォーターマーク追加、数分かかる可能性
  • データ同期:システム間のデータ同期、所要時間が不確定

非同期タスクの核心思想

時間のかかる操作を「リクエスト-レスポンス」のメインフローから切り離し、バックグラウンドのキューで非同期処理します。ユーザーがリクエストを送信すると即座に「受信しました、処理中です」という応答が返り、処理完了後に通知、ポーリング、またはWebSocketで結果を知らせます。


1. 同期 vs 非同期:ある注文の物語 ​

ユーザーが注文を送信するとき、バックエンドは多くのことを行う必要があります:在庫の減算、注文レコードの作成、確認メールの送信、レコメンドシステムの更新、監査ログの記録……

同期モードでは、これらの操作は直列に実行され、ユーザーはすべての操作が完了するまで結果を見ることができません。非同期モードでは、核心的な操作(在庫減算、注文作成)だけを完了し、残りの操作はキューに投入してバックグラウンドで処理します。

Synchronous vs Asynchronous Processing
Click the button to compare the two processing modes
User request
Waiting to submit
→
Server processing
⬜Reserve inventory50ms
⬜Create order100ms
⬜Send confirmation email800ms
⬜Update recommendation system600ms
⬜Write audit log300ms
比較次元同期処理非同期処理
ユーザー待ち時間全操作の合計時間核心操作の時間のみ
システムスループット低(スレッドがブロックされる)高(スレッドを素早く解放)
失敗の影響非核心の失敗が全体の失敗に非核心の失敗はメインフローに影響しない
実装の複雑さシンプル追加のキューインフラが必要
データ一貫性強整合性結果整合性

いつ非同期を使うべきか?

3つの判断基準:時間がかかる(1-2秒以上)、非核心的(失敗してもメインフローに影響しない)、遅延可能(すぐに結果が必要でない)。このうち2つ以上に該当すれば、非同期化を検討すべきです。


2. プロデューサー・コンシューマーモデル:タスクの「生産ライン」 ​

非同期タスクキューの核心は古典的な プロデューサー・コンシューマーパターン(Producer-Consumer Pattern) です。このパターンには3つの役割があります:

  • プロデューサー(Producer):タスクを生成する側。通常はユーザーリクエストを処理するWebサーバー
  • キュー(Queue):処理待ちタスクを保存するバッファ。通常Redis、RabbitMQなどで実装
  • コンシューマー(Consumer/Worker):キューからタスクを取り出して実行するワーカープロセス
Worker Pool Model
Watch tasks get distributed to different workers
Worker count: 3
Task queue (0)
Queue is empty
→
Workers
Worker 1
💤 Idle
Completed: 0
Worker 2
💤 Idle
Completed: 0
Worker 3
💤 Idle
Completed: 0
→
Completed (0)
None yet

キューの3大価値

  1. 疎結合:プロデューサーは誰がタスクを処理するか知る必要がなく、コンシューマーはタスクがどこから来るか知る必要がない
  2. ピークカット:バーストトラフィック時はタスクがまずキューに溜まり、コンシューマーは自分のペースで処理
  3. 信頼性:タスクはキューに永続化され、コンシューマーがクラッシュしても失われない
コンポーネント責務一般的な実装
メッセージミドルウェアタスクメッセージの保存と転送Redis、RabbitMQ、Kafka
シリアライザタスクパラメータのシリアライズ/デシリアライズJSON、MessagePack、Pickle
スケジューラ定期タスクと遅延タスクの管理Cron、APScheduler、node-cron
結果ストレージタスク実行結果の保存Redis、データベース、S3

3. 信頼性の確保:タスクは「失われて」も「重複して」もいけない ​

分散環境では、ネットワークの揺らぎ、サービスの再起動、リソース不足などの問題がいつでも発生する可能性があります。非同期タスクシステムには完全な信頼性保証機構が必須です。

最も核心的な2つの問題:タスク消失(コンシューマーが処理途中でクラッシュ)と重複実行(タスクが2回配信された)。

Task Retry and Backoff Strategies
Simulate the retry process after a task fails
Fixed interval
Every retry waits for the same duration. It is simple, but can cause retry storms.
Delay formula:delay = 2s

信頼性の三種の神器

  1. ACK機構:コンシューマーがタスク処理完了後に確認応答(ACK)を送信。未確認のタスクは再配信される
  2. リトライ戦略:タスク失敗後、戦略に従ってリトライ。指数バックオフ + ジッターがベストプラクティス
  3. 冪等性設計:同じタスクを複数回実行しても1回実行したのと同じ効果。一意のIDによる重複排除で実現
機構解決する問題実現方法
ACK確認タスク消失処理完了後に手動確認。タイムアウト未確認は再配信
デッドレターキュー(DLQ)繰り返し失敗する「毒メッセージ」リトライ上限超過後、デッドレターキューに転送し手動対応
冪等性重複実行タスクの一意IDで重複排除。データベースの一意制約
優先度キュータスクスタベーション高優先度タスクを優先処理し、低優先度タスクによるブロックを防止
タイムアウト制御タスクのフリーズ最大実行時間を設定し、タイムアウト時に自動終了してリトライ

4. フレームワーク選定:最適なツールを選ぶ ​

言語エコシステムごとに異なる非同期タスクフレームワークがあり、機能の豊富さ、パフォーマンス、使いやすさにそれぞれ特徴があります。フレームワークを選ぶ際は、まず技術スタックを考慮し、次にプロジェクトの規模と要件に基づいて決定します。

Popular Async Task Frameworks
Click a framework to inspect the details
Celery
Python
★★★★★
Sidekiq
Ruby
★★★★★
Bull
Node.js
★★★★★
RQ
Python
★★★★★
Kafka Streams
Java/JVM
★★★★★
CeleryPython
The most popular distributed task queue in the Python ecosystem. It supports multiple brokers such as RabbitMQ and Redis, with a broad feature set and active community.
Core features:
Scheduled tasksTask chainsResult backendAutomatic retriesPriority queuesTask routing
Typical scenarios:
Data pipelines, email sending, report generation, machine learning training jobs

選定アドバイス

  • Pythonプロジェクト:中〜大規模はCelery、小規模はRQ
  • Node.jsプロジェクト:BullMQ(Bullの次世代版)が第一候補
  • Rubyプロジェクト:Sidekiqがほぼ唯一の選択肢
  • Javaプロジェクト:SpringエコシステムはSpring Batch、高スループットはKafka Streams
  • Goプロジェクト:Asynq(Redisベース)またはMachinery

すでにRedisを使用しているプロジェクトであれば、Redisベースのソリューション(Celery+Redis、BullMQ、Sidekiq)が最も簡単なスタート地点です。


まとめ ​

非同期タスクキューはバックエンドアーキテクチャに不可欠なインフラです。時間のかかる操作をエレガントに処理し、ユーザー体験を向上させながらシステムスループットを高めます。

本章の重要ポイントを振り返ります:

  1. 非同期化の判断基準:時間がかかる、非核心的、遅延可能。2つに該当すれば非同期化すべき
  2. プロデューサー・コンシューマーモデル:Producer → Queue → Consumer、三者が疎結合で協調
  3. ワーカープール:複数Workerが並列消費し、処理能力を向上
  4. 信頼性の確保:ACK確認 + リトライ戦略 + 冪等性、三者が揃って初めて完全
  5. フレームワーク選定:技術スタックとプロジェクト規模に基づいて選択。Redisが最も一般的なメッセージミドルウェア

参考資料 ​