メッセージキュー
処理の依頼をいったん行列に積み、非同期に処理する仕組み。システム間の緩衝材。
概要
メッセージキューとは、処理の依頼(メッセージ)をいったん「行列(キュー)」に積んでおき、別のプログラムが後から順に取り出して処理する仕組みです。メッセージを積む側をプロデューサ(生産者)、取り出して処理する側をコンシューマ(消費者)と呼び、両者の間に立つキュー本体はブローカと呼ばれる専用のミドルウェア(RabbitMQ、Amazon SQS、Apache Kafka など)が担います。
たとえば会員登録の完了メール。ユーザーへの応答はメールが実際に送られるのを待つ必要はありません。サーバ は「メール送信」という依頼をキューに積んですぐ応答を返し、別のワーカープロセスが後からキューを読んで送信します。画像や動画の変換、帳票生成、外部 API への連携など、「今すぐ結果が要らない処理」をリクエストの外へ逃がすのが典型的な使い方です。
本質は、送り手と受け手を時間的にも構造的にも切り離すことにあります。送り手は受け手が今動いているかを知らなくてよく、受け手は自分のペースで処理できる。この「疎結合」こそが、メッセージキューがシステム設計の中心的な道具である理由です。
なぜ生まれたか
システム同士を直接つなぐ同期的な連携には、宿命的な弱さがあります。呼び出し先が落ちていれば呼び出し元も失敗し、呼び出し先が遅ければ呼び出し元も待たされる。つまり、つながったシステムは可用性と速度の運命を共有してしまうのです。企業内の多数のシステムを連携させる場面ではこの問題が深刻で、1990年代からメッセージ指向ミドルウェア(IBM MQ など)が「相手が今いなくても届く、非同期の郵便受け」としてこの結合を断つ役割を担ってきました。
Web の時代には、もう一つの動機が加わります。負荷の波です。テレビ放映やセールで瞬間的にリクエストが殺到したとき、すべてを同期処理していればサーバは波の高さそのままの負荷を受けて倒れます。キューを挟めば、積まれる速度がどれだけ速くても、処理する速度は自分たちで決められる。波を行列に変えて平らにならす——この緩衝材としての価値が、メッセージキューを大規模Webシステムの標準部品に押し上げました。
詳細
積み降ろしの基本フロー
基本の流れは単純です。プロデューサはブローカにメッセージを送信した時点で自分の仕事を終え、応答を返せます。メッセージはキューに永続化され、コンシューマが取り出して処理し、完了したら「確認応答(ack)」をブローカに返します。ack が返って初めてメッセージはキューから消えるため、コンシューマが処理中にクラッシュしても、メッセージは失われず別のコンシューマに再配達されます。
キューが「負荷の波」と「消費者の障害」を吸収する様子は、下のシミュレータで体験できます。
メッセージを送ってみてください。消費者は1件/秒の一定ペースで捌きます。
この構造から、スケーリングの柔軟さが生まれます。キューが積み上がってきたらコンシューマの台数を増やせばよく、逆に夜間は減らせばよい。負荷対策がコンシューマ側の スケーリング という単純な操作に還元されるのです。キューの長さ(滞留数)は、システムの健全性を示す代表的な 監視 指標になります。
二つの配送モデル
メッセージングには大きく二つのモデルがあります。一つはキュー型(ポイントツーポイント)で、1件のメッセージは複数のコンシューマのうちどれか1つだけが処理します。ジョブの分担に向く形です。もう一つはパブサブ型(publish/subscribe)で、1件のメッセージ(イベント)を購読者全員がそれぞれ受け取ります。「注文が確定した」という一つの出来事を、在庫・通知・分析のサービスがそれぞれ独立に処理する、といった マイクロサービス のイベント駆動連携はこちらの形です。Kafka のようなログ型のブローカは、メッセージを消さずに保持し、コンシューマ側が「どこまで読んだか」を管理する方式で、パブサブと再読(リプレイ)を強力にサポートします。
覚悟しておくべき性質
メッセージキューを使うなら、いくつかの性質を設計に織り込む必要があります。最も重要なのが配送保証です。多くのブローカの現実的な保証は「少なくとも1回(at-least-once)」、つまり同じメッセージが2回届くことがあるという意味です。ネットワーク断で ack が届かなければ再配達されるからです。したがってコンシューマは、同じメッセージを2回処理しても結果が変わらないように(冪等に)作るのが鉄則です。順序も無条件には保証されません。複数のコンシューマが並行処理すれば完了順は前後するため、順序が本質的な処理ではメッセージのグループ化やパーティション設計が必要です。
典型的な落とし穴と定番の対策
実務でよく踏む問題には名前と定石があります。何度処理しても失敗し続ける「毒メッセージ」がキューの先頭で詰まる問題には、規定回数失敗したメッセージを退避させるデッドレターキュー(DLQ)を用意します。コンシューマの処理能力を超えてキューが積み上がり続ける問題は、緩衝材が「遅延の貯金箱」に変わったサインで、コンシューマ増強か流入制限が要ります。また、非同期化はユーザー体験の設計も変えます。「注文を受け付けました(処理は完了ではない)」という状態をユーザーにどう見せるか、処理失敗をどう通知するか——技術だけでなく体験側の設計が伴って初めて完成します。
使いどころの見極め
すべてを非同期にすればよいわけではありません。残高照会のように「今の答え」が必要な処理は同期が自然ですし、キューを挟むことは、ブローカという新たな運用対象と、結果整合性という考えることの増加を意味します。判断の軸は「その処理の結果を、リクエストの応答に含める必要が本当にあるか」です。なくてよいなら、キューに逃がすことで応答は速くなり、システム同士は互いの障害から守られます。この見極めが、メッセージキューという道具の使いこなしの核心です。