【比較】キューとトピック(メッセージング)の違い¶
概要¶
非同期メッセージングでメッセージの宛先(デスティネーション)には大きく 2 種類あります。「キュー(queue)」は point-to-point(1 対 1) モデルの宛先で、メッセージは特定のキューに送られ、ちょうど 1 つのコンシューマだけが受け取って消費します。複数のコンシューマがぶら下がっていても、各メッセージは(基本的に)どれか 1 つだけに届き、互いに仕事を奪い合います(competing consumers)。Jakarta Messaging(旧 JMS)も「キューに送られた各メッセージは確実に 1 つのコンシューマに配送・消費される」と定義しています。一方「トピック(topic)」は publish/subscribe(pub/sub、1 対多) モデルの宛先で、パブリッシャがトピックに送ったメッセージは、そのトピックを購読している各サブスクライバそれぞれにコピーが届きます(fan-out)。掲示板に貼った 1 枚の告知を、見にきた全員が読むイメージです。
両者が混同される最大の理由は、どちらも「メッセージを介して送信者と受信者を疎結合する」点が同じで、ブローカ製品(RabbitMQ、ActiveMQ、Kafka など)が両方を扱うためです。しかし配送セマンティクスが決定的に違います。キューは「1 メッセージ=1 コンシューマ(処理を分担・負荷分散したい)」、トピックは「1 メッセージ=全サブスクライバ(同じイベントを複数の関心先に配りたい)」。AWS でいえば SQS がキュー(point-to-point)、SNS がトピック(pub/sub の fan-out)に対応します。ただし Apache Kafka はトピックを基盤としつつコンシューマグループでこの線引きを意図的にぼかしており、後述のとおり「グループ内では分担=キュー的」「グループをまたぐとブロードキャスト=pub/sub 的」の両方を 1 つの仕組みで実現します。
詳細比較¶
| 項目 | キュー (Queue / point-to-point) | トピック (Topic / publish-subscribe) |
|---|---|---|
| モデル | point-to-point(1 対 1) | publish/subscribe(1 対多) |
| 1 メッセージの届き先 | (競合する複数のうち)ちょうど 1 つのコンシューマ | 購読中のサブスクライバ全員(各自にコピー) |
| 狙い | 処理の分担・負荷分散(competing consumers) | 同じイベントを複数の関心先へ配る(fan-out) |
| コンシューマを増やすと | スループットが上がる(仕事を分け合う) | 各サブスクライバが全件受け取る(増やしても分担しない) |
| 送信者と受信者の関係 | 送信時に受信者がいなくてもキューが保持し後で 1 つが消費 | 標準では購読中のサブスクライバにのみ届く(永続サブスクリプションで不在時も保持可) |
| 代表的なマッピング | Amazon SQS、JMS Queue、RabbitMQ のワークキュー | Amazon SNS、JMS Topic、Kafka トピック(+コンシューマグループ) |
| 典型用途 | ジョブ/タスク処理、注文処理など「1 回だけ確実に処理」 | イベント通知、複数システムへの同報、監査・分析への複製 |
Jakarta Messaging(JMS)仕様は「point-to-point ではメッセージは特定のキューに宛てられ、各メッセージは確実に 1 つのコンシューマに配送・消費される」「pub/sub ではクライアントはトピック(掲示板のようなもの)にメッセージを宛て、トピックに送られた各メッセージは各サブスクリプションに追加され、対象の各サブスクライバに配送される」と定義しています。AWS 公式ドキュメントも「SQS はキューサービスで、通常は単一のサブスクライバでメッセージを処理する(順序・喪失防止が重要なワークフロー向け)」「SNS はパブリッシャがトピック経由で複数のサブスクライバへメッセージを送る。トピックに publish されたメッセージが複数エンドポイントへ複製・push されるのが Fanout シナリオ」と明記しています。
よくある誤解¶
-
「キューにコンシューマを 3 台つなげば、同じメッセージが 3 台に届く」は誤り。 キューは point-to-point なので、1 メッセージは(競合する複数のうち)1 台だけが受け取ります。3 台つなぐのは処理を分担して速くするため(competing consumers)で、ブロードキャストではありません。全員に同じメッセージを配りたいならトピック(pub/sub)を使います。JMS 仕様も「各メッセージは 1 つのコンシューマに消費される」と明記しています。
-
「トピックでコンシューマを増やせばキューのように負荷分散できる」は誤り。 標準の pub/sub トピックでは、サブスクライバを増やすと各サブスクライバが全件を受け取るだけで、処理は分担されません。負荷分散したいならキュー、または「サブスクライバの中でさらに分担する」仕組み(Kafka のコンシューマグループ、JMS の shared subscription 等)が必要です。トピックそのものは fan-out であって負荷分散機構ではありません。
-
「Kafka のトピックはただの pub/sub トピックだ(SNS と同じ)」は不正確。 Kafka はトピックを土台にしつつコンシューマグループでキュー的にも pub/sub 的にも振る舞います。Kafka 公式は「同一コンシューマグループのインスタンスにレコードを負荷分散する(キュー的)」「異なるコンシューマグループならレコードは全コンシューマプロセスにブロードキャストされる(pub/sub 的)」と説明しており、グループ設計次第で挙動が変わります。「Kafka=pub/sub だけ」と捉えると誤ります。
-
「トピックなら送信時に受信者がいなくても後で必ず受け取れる」は誤り(条件付き)。 標準の(非永続)サブスクリプションでは、購読していない間に発行されたメッセージは届きません。不在中のメッセージも受け取りたい場合は永続サブスクリプション(durable subscription)や、トピック→キューへ fan-out して各キューで保持する構成(例: SNS→SQS)が必要です。pub/sub だから自動で取りこぼさない、わけではありません。
実務での選び分け¶
- 1 つのタスクを誰か 1 人が確実に 1 回処理すればよい(ジョブ処理・注文処理) → キュー(SQS / JMS Queue)。ワーカーを増やせばそのままスループットが上がる。順序・喪失防止が重要な処理に向く。
- 1 つのイベントを複数の独立したシステムに同報したい(通知・分析複製・監査) → トピック(SNS / JMS Topic)。サブスクライバを足すだけで関心先が増える。各サブスクライバは互いに独立。
- 「全システムに配りつつ、各システム内ではワーカーで分担」したい → トピック→各キューへ fan-out(SNS→複数 SQS)か、Kafka のコンシューマグループ(グループ間は pub/sub、グループ内は分担)。
- 不在中のメッセージも取りこぼしたくない → 永続サブスクリプション、または pub/sub の各購読先をキューで受ける(SNS→SQS のように保持層を挟む)。
- Kafka を選ぶとき → 「トピック=pub/sub」と短絡せず、コンシューマグループの設計(同一グループ=分担/別グループ=ブロードキャスト)で意図する配送になっているか必ず確認する。
ひとことまとめ¶
キューは point-to-point で「1 メッセージを(競合する中の)ちょうど 1 コンシューマが消費する=処理の分担・負荷分散」、トピックは publish/subscribe で「1 メッセージを購読中の全サブスクライバへコピー配送する=fan-out」です。SQS がキュー、SNS がトピックに対応し、Kafka はコンシューマグループでこの線引きを設計次第に変えられます。
出典・参考¶
- Jakarta Messaging Concepts — Jakarta EE Tutorial — point-to-point は「各メッセージは特定のキューに宛てられ、確実に 1 つのコンシューマに配送・消費される」、pub/sub は「クライアントはトピック(掲示板のようなもの)にメッセージを宛て、各メッセージは各サブスクリプションに追加され各サブスクライバへ配送される」
- What is Amazon SQS? — Amazon Simple Queue Service Developer Guide — SQS はキューサービスで「通常は単一のサブスクライバでメッセージを処理する(順序・喪失防止が重要なワークフロー向け)」、Publisher-subscriber messaging は「No」、より広い配信は SNS との連携で fanout
- What is Amazon SNS? — Amazon Simple Notification Service Developer Guide — SNS はパブリッシャからサブスクライバへトピック経由でメッセージ配送、Fanout は「SNS トピックに publish されたメッセージが複数エンドポイント(SQS/Lambda/HTTP(S) 等)へ複製・push される」
- Apache Kafka Documentation: Introduction (Consumers) — 「キューではコンシューマのプールから各レコードが 1 つに届き、pub/sub では全コンシューマにブロードキャストされる」、「同一コンシューマグループならレコードはインスタンス間で負荷分散され、異なるコンシューマグループなら各レコードは全コンシューマプロセスにブロードキャストされる」