Skip to content

メッセージキューとイベント駆動

🎯 核心問題

システムの結合度が高く、トラフィックが急増したとき、コアリンクの安定性をどう確保するか? メッセージキューは現代の分散システムにおける「バッファ」であり「デカップリングツール」である。本記事では実際のケース(レストランの番号呼び出し、宅配便の仕分け、フラッシュセールシステム)を通じて、メッセージキューの設計哲学とエンジニアリング実践を深く理解する。


1. なぜ「メッセージキュー」が必要なのか?

1.1 実際のケースから考える:Taobao注文システムの進化

2012年、Taobaoの注文システムは深刻な障害に見舞われた。ダブルイレブン(独身の日)の0時、トラフィックが瞬間的に殺到し、注文サービスが在庫サービス、決済サービス、物流サービスを直接呼び出した… 連鎖全体がドミノ倒しのように次々とダウンした。

当時のアーキテクチャ(密結合):

ユーザー注文 → 注文サービス → 同期呼び出し 在庫サービス → 同期呼び出し 決済サービス → 同期呼び出し 物流サービス
                              ↓                    ↓                    ↓
                           応答 200ms           応答 500ms           応答 300ms

⚠️ 密結合の致命的な問題

  • 総応答時間 = 200 + 500 + 300 = 1000ms(ユーザーは1秒待たされる)
  • 在庫サービスがダウン → 注文サービスもダウン(スレッドプール枯渇)
  • 決済サービスが遅延 → 連鎖全体が遅くなる
  • 水平スケーリング不可 → 垂直スケーリングのみ(高コストかつ限界あり)

改善後のアーキテクチャ(メッセージキュー導入):

ユーザー注文 → 注文サービス → 「注文作成」メッセージ送信 → 即時返却(50ms)

                              メッセージキュー(Kafka)

              ┌─────────────┬─────────────┬─────────────┐
              ▼             ▼             ▼             ▼
         在庫サービス    決済サービス    物流サービス    通知サービス
         (非同期減算)  (非同期処理)  (非同期作成)  (非同期送信)

✨ 改善後の効果

  • ユーザー応答時間 = 50ms(体感20倍向上)
  • 在庫サービスがダウン → メッセージはキューに保持され、復旧後に処理継続
  • 決済サービスが遅延 → 注文作成に影響しない
  • 水平スケーリング可能 → コンシューマーインスタンスを追加するだけ

1.2 メッセージキューの日常的な比喩

レストランの番号呼び出しシステム

人気レストランに行く場面を想像してみよう:

  • 番号呼び出しなし:客は窓口で立って待たなければならず、窓口は限られ、後ろの人は長蛇の列、レストランは大きなプレッシャー
  • 番号呼び出しあり:注文後に番号を受け取り、まず座って、番号が呼ばれたら料理を受け取りに行く

メッセージキューはソフトウェアシステムの「番号呼び出しシステム」である

  • プロデューサー(注文する人) → メッセージ(注文)をキューに入れる
  • キュー(番号呼び出し機) → メッセージを一時保存
  • コンシューマー(シェフ) → 自分のペースでメッセージを処理する
Peak Shaving: flatten traffic spikes
Simulate a burst and see how a queue protects backend systems
Processing capacity (Consumer)200 req/s
Maximum backend processing speed
Queue capacity (Queue Size)2000
Maximum requests the message queue can buffer
Current inbound traffic
100 req/s
Queue backlog
0 msgs
Actual processing rate
0 req/s
Rejected requests (rate limited)
0 req
Inbound traffic (user requests)Processed traffic (system load)Queue backlog
💡
Core principle: When inbound traffic (blue) exceeds processing capacity (green line), extra requests are stored in the message queue (orange area).
After the traffic peak passes, the system keeps processing the backlog at full speed until the queue is empty. This is peak shaving.

2. メッセージキューとは?(定義 + コアの三要素)

2.1 「メッセージキュー」とは?

🤔 用語解説

メッセージキュー(Message Queue, MQ) はメッセージを保存するコンテナであり、プロデューサーがメッセージを入れ、コンシューマーがそこからメッセージを取り出して処理する。「非同期通信」を実現し——送信側は受信側の処理完了を待つ必要がない。

同期 vs 非同期

  • 同期:電話のように、相手が応答しなければ会話できない
  • 非同期:WeChatのように、送信すればよく、相手は時間があるときに見る

これは友人に電話をかける(同期)のと WeChat を送る(非同期)の違いである。

2.2 メッセージキューのコアの三要素

要素一:プロデューサー(Producer)

役割:メッセージを作成しキューに送信する。

日常的な比喩:プロデューサーは「差出人」のようなもので、手紙(メッセージ)を郵便局(キュー)に届ける。

主要な設計ポイント
  • 送信方式:同期送信(信頼性が高いがブロッキング) vs 非同期送信(高性能だがコールバック処理が必要)
  • メッセージ確認:Broker の確認を待つ(At Least Once) vs 送信して忘れる(At Most Once)
  • 失敗処理:リトライ戦略、ローカルログバックアップ、デッドレターキュー

要素二:コンシューマー(Consumer)

役割:キューからメッセージを取得し処理する。

日常的な比喩:コンシューマーは「受取人」のようなもので、メールボックス(キュー)から手紙(メッセージ)を取り出して処理する。

主要な設計ポイント
  • 消費モード:プッシュモード(Push、Broker が能動的にプッシュ) vs プルモード(Pull、コンシューマーが能動的に取得)
  • 消費確認:自動 ACK(効率的だがメッセージ喪失の可能性あり) vs 手動 ACK(信頼性が高いがタイムアウト処理が必要)
  • 並行制御:シングルスレッド順次消費 vs マルチスレッド並列消費
  • 失敗処理:リトライ戦略、デッドレターキュー、補償メカニズム

要素三:Broker(メッセージブローカー)

役割:メッセージの受信、保存、転送を行う。

日常的な比喩:Broker は「郵便局」や「宅配便の中継所」のようなもので、手紙の受付、仕分け、配達を担当する。

主要な設計ポイント
  • 保存モデル:メモリ保存(低レイテンシ) vs ディスク保存(高信頼性)
  • レプリケーション戦略:マスタースレーブレプリケーション、マルチレプリカ同期
  • 高可用性メカニズム:クラスターデプロイ、自動フェイルオーバー
  • 拡張性:パーティション(Partition)、シャーディング(Sharding)

3. 核心問題その一:システムをどうデカップリングし、「一発触発全身」を避けるか?

3.1 密結合の悲劇:一つのサービスがダウンすると全滅

シーン再現:あるECプラットフォームの初期アーキテクチャ

注文サービスが下流サービスを直接呼び出す:
┌─────────────┐
│  注文サービス  │
└──────┬──────┘

       ├───────────┬───────────┬───────────┐
       ▼           ▼           ▼           ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│在庫サービス│ │決済サービス│ │物流サービス│ │SMSサービス │
│  200ms   │ │  500ms   │ │  300ms   │ │  100ms   │
└──────────┘ └──────────┘ └──────────┘ └──────────┘

📊 問題点分析表

問題点具体的な現象結果
連鎖障害在庫サービスがダウン、注文サービスの同期呼び出しがタイムアウト注文サービスのスレッドプール枯渇、新規リクエスト処理不可
応答遅延すべての下流サービスの応答を待たなければならないユーザーは1秒以上待たされ、体験が極めて悪い
拡張困難ポイントサービスを追加する場合、注文サービスのコード修正が必要リリースサイクルが長くなり、リスクが増加
リソース浪費注文サービスはSMSサービスを待たなければならないデータベース接続が長時間占有される

3.2 デカップリング案:メッセージキューを「中間層」として導入

デカップリング後のアーキテクチャ:

注文サービスはメッセージ送信のみ担当し、誰が消費するかは関知しない:

┌─────────────┐
│  注文サービス  │ ──「注文作成」メッセージ送信──┐
└─────────────┘                       │

                            ┌───────────────────┐
                            │   メッセージキュー    │
                            │  (Kafka/RabbitMQ) │
                            │   - 信頼性のある保存  │
                            │   - マルチレプリカ    │
                            │   - 順序保証        │
                            └─────────┬─────────┘

              ┌───────────────────────┼───────────────────────┐
              │                       │                       │
              ▼                       ▼                       ▼
       ┌──────────────┐      ┌──────────────┐      ┌──────────────┐
       │  在庫サービス   │      │  決済サービス   │      │  物流サービス   │
       │  注文イベント購読│      │  注文イベント購読│      │  注文イベント購読│
       └──────────────┘      └──────────────┘      └──────────────┘
🔗System Decoupling DemoFrom tight coupling to loose coupling
❌ The fatal problem of tight coupling
Order service
Create order
Call inventory service
Call points service
Call notification service
Notification service
Send SMS/email
⚠️Strong dependency: notification failure blocks order creation
⚠️Slow response: total time = 300ms + 500ms + 400ms = 1200ms
⚠️Hard to extend: adding a service requires changing order code
💡Core idea:Synchronous calls create strong dependencies and slow responses; asynchronous messaging decouples systems, improves response speed, and scales more easily.

✨ デカップリングの利点

次元デカップリング前デカップリング後
障害隔離在庫ダウン = 注文ダウン在庫ダウン時、メッセージはキューに保留、復旧後に消費
応答時間1000ms(同期待機)50ms(メッセージ送信後即時返却)
拡張性新規サービス追加時に注文コード修正必要新規サービスはトピック購読のみ
システム複雑性注文サービスが下流に強く依存注文サービスはメッセージキューのみに依存

3.3 デカップリングの本質:「直接呼び出し」から「イベント駆動」へ

思考モデルの転換:

従来の考え方(命令型):
「注文サービスが在庫サービスに命令:在庫を減らせ!」
  ↓ 直接呼び出し
  ↓ 結合度が高く、呼び出し先がオンラインである必要がある
  ↓ 呼び出し元は呼び出し先のインターフェースを知っている必要がある

イベント駆動の考え方(宣言型):
「注文サービスが宣言:注文が作成された。関心のある者が処理せよ。」
  ↓ メッセージキューにイベント送信
  ↓ デカップリング、コンシューマーはオフラインでも可
  ↓ プロデューサーはコンシューマーの存在を知る必要がない

4. 核心問題その二:ピークカットとバレーフィルでトラフィック急増にどう対処するか?

4.1 フラッシュセールシーン:10万QPSをどう安定的に処理するか?

シーン再現:あるECプラットフォームのダブルイレブンフラッシュセール、ピーク時10万QPSが見込まれるが、データベースは1000QPSしか耐えられない。

直接的な衝撃の結果:

ユーザーリクエスト ──→ アプリケーションサーバー ──→ データベース
    10万/s             10万/s                1000/s(限界)

                                           コネクションプール枯渇
                                           応答タイムアウト
                                           データベースクラッシュ

                                           雪崩効果(データベースに依存する全サービスがダウン)

🌊 用語解説

QPS(Queries Per Second):秒間クエリ数。システムのスループットを測る指標。

10万QPS は毎秒10万リクエストがあることを意味し、10万人が同時に店に押し寄せるようなものである。

4.2 ピークカット・バレーフィル案:メッセージキューを「貯水池」として

アーキテクチャ設計:

┌───────────────────────────────────────────────────────────────────────┐
│                        フラッシュセールシステムアーキテクチャ               │
├───────────────────────────────────────────────────────────────────────┤
│                                                               │
│  第一層:ゲートウェイ層(ハードリミット)                              │
│  ┌───────────────────────────────────────────────────────────────┐  │
│  │  - トークンバケット制限:10万/s → 1万/s(90%のリクエストを破棄)  │  │
│  │  - CDN 静的リソースキャッシュ(商品詳細ページ)                  │  │
│  │  - キャプチャ/待機ページ(ピークカット第一層)                   │  │
│  └───────────────────────────────────────────────────────────────┘  │
│                            │                                 │
│                            ▼                                 │
│  第二層:サービス層(ソフトリミット)                                │
│  ┌───────────────────────────────────────────────────────────────┐  │
│  │  - Nginx制限:1万/s → 5000/s                            │  │
│  │  - Redis在庫事前減算(アトミック操作):                     │  │
│  │    * Luaスクリプトでアトミック性を保証                       │  │
│  │    * 在庫不足時は直接「売り切れ」を返却                       │  │
│  │  - 注文トークン生成(待機証憑)                             │  │
│  └───────────────────────────────────────────────────────────────┘  │
│                            │                                 │
│                            ▼                                 │
│  第三層:メッセージキュー層(コアのピークカット)                      │
│  ┌───────────────────────────────────────────────────────────────┐  │
│  │  Kafka/RocketMQ:                                     │  │
│  │  - バッチ書き込み:5000/s → 1000/s(DB許容範囲)          │  │
│  │  - メッセージ永続化:ディスク書き込みでメッセージ喪失防止       │  │
│  │  - マルチパーティション並列消費:スループット向上            │  │
│  │  - 消費オフセット管理:障害復旧対応                         │  │
│  │                                                       │  │
│  │  主要指標モニタリング:                                     │  │
│  │  - 生産レート(Produce Rate)                             │  │
│  │  - 消費レート(Consume Rate)                             │  │
│  │  - メッセージラグ(Lag)                                   │  │
│  └───────────────────────────────────────────────────────────────┘  │
│                            │                                 │
│                            ▼                                 │
│  第四層:消費層(非同期処理)                                      │
│  ┌───────────────────────────────────────────────────────────────┐  │
│  │  注文処理コンシューマー(マルチインスタンス):                  │  │
│  │  - Kafka からメッセージを取得(1000/s、DB能力に合わせる)     │  │
│  │  - DBトランザクション:注文作成 + 在庫減算                     │  │
│  │  - 注文ステータスを「作成済み」に更新                          │  │
│  │  - 注文作成成功通知を送信(メール/SMS/プッシュ)               │  │
│  │  - メッセージ消費確認(ACK)                                  │  │
│  │                                                         │  │
│  │  コンシューマースケーリング戦略:                              │  │
│  │  - Lag > 10000 の場合、コンシューマーインスタンスを自動追加      │  │
│  │  - Lag < 1000 の場合、コンシューマーインスタンスを削減(コスト削減)│  │
│  └───────────────────────────────────────────────────────────────┘  │
│                                                               │
└───────────────────────────────────────────────────────────────────────┘
Peak Shaving: flatten traffic spikes
Simulate a burst and see how a queue protects backend systems
Processing capacity (Consumer)200 req/s
Maximum backend processing speed
Queue capacity (Queue Size)2000
Maximum requests the message queue can buffer
Current inbound traffic
100 req/s
Queue backlog
0 msgs
Actual processing rate
0 req/s
Rejected requests (rate limited)
0 req
Inbound traffic (user requests)Processed traffic (system load)Queue backlog
💡
Core principle: When inbound traffic (blue) exceeds processing capacity (green line), extra requests are stored in the message queue (orange area).
After the traffic peak passes, the system keeps processing the backlog at full speed until the queue is empty. This is peak shaving.

4.3 ピークカット・バレーフィルの数学的原理

トラフィック平滑化効果:

元のトラフィック(尖峰):              平滑化後トラフィック:

10万/s │    ╱╲                  1000/s │████████████████
       │   ╱  ╲                        │
       │  ╱    ╲                       │
 1000/s│╱        ╲                 0/s │
       └───────────────               └────────────────
       0s   1s   2s                   0s              20s

元:10万/s ピーク、1秒間継続
平滑化:1000/s 一定レート、100秒間継続

主要な計算式:

キュー長 = プロデューサーレート × 継続時間 - コンシューマーレート × 継続時間
        = 100,000 × 1 - 1,000 × 1
        = 99,000 メッセージ(ピーク時のキュー滞留)

全メッセージ消費完了までの時間 = キュー長 / コンシューマーレート
                            = 99,000 / 1,000
                            = 99 秒

5. 核心問題その三:メッセージの非喪失、非重複、順序性をどう保証するか?

5.1 メッセージ信頼性:三つの防衛線

メッセージは三つの段階で失われる可能性がある:プロデューサー送信時、Broker保存時、コンシューマー処理時。

🛡️ 三つの防衛線

防衛線1:プロデューサー確認(Producer ACK)

  • メッセージ送信時、Broker の受信確認を待つ
  • 確認が受信できない場合、リトライまたはローカルログに記録

防衛線2:Broker永続化

  • メッセージをディスクに書き込み、メモリのみに保持しない
  • マルチレプリカ同期でデータ喪失を防止

防衛線3:コンシューマー確認(Consumer ACK)

  • メッセージ処理後、手動で確認(ACK)
  • 処理失敗時は確認せず、Broker が再配信
🛡️Message Reliability DemoThree defense lines keep messages from being lost
Line 1
Producer ACK
📤
Producer
Send message
📨
Message
ACK confirmation
📦
Broker
Receive and store
💡 If no ACK is received, the producer retries or records a local log.
Line 2
Broker persistence
Memory storage
Fast, but lost on restart
❌ High risk
vs
🔄 Multi-replica sync
Messages are synced to 3 nodes, so data is not lost even if 1 node fails.
Message persisted and safe
Line 3
Consumer ACK
1
Pull message
Fetch message from Broker
2
Process message
Run business logic
3
Manual ACK
Confirm after processing
Auto ACK
Efficient but can lose messages
⚠️ Not recommended
💡 If processing fails, no ACK is sent and the Broker redelivers.
🎯
All three defense lines are required:Producer ACK → Broker persistence → Consumer ACK

5.2 メッセージの重複消費にどう対処するか?

メッセージ重複は以下のシナリオで発生しうる:

  1. プロデューサーリトライ:プロデューサーがメッセージ送信後 ACK 未受信で、同一メッセージを再送
  2. コンシューマー ACK タイムアウト:コンシューマー処理完了したが ACK がタイムアウトし、Broker が再配信
  3. ネットワークジッター:コンシューマー ACK が Broker に届かず、Broker が未消費と判断
  4. コンシューマー再起動:コンシューマー再起動後、同一バッチのメッセージを再消費

💡 冪等性

冪等性:同一操作を複数回実行しても、1回実行した時と同じ効果になること。

日常生活における冪等性

  • 冪等:エレベーターのボタンを押す(10回押しても1回押しても、エレベーターは来る)
  • 非冪等:送金(10元送金を2回実行すると20元送金される)

技術的解決策:各メッセージに一意のIDを生成し、処理前に処理済みかどうかをチェックする。

🔄Idempotence DemoRepeated consumption does not create side effects
❌ Non-idempotent operation: bank transfer
Repeated consumption can debit multiple times
Disabled
Processing log
No logs yet. Click the button to start.
❌ No idempotence protection
Debit ¥100
Duplicate consumption causes multiple debits
✅ With idempotence protection
Debit ¥100
Duplicate requests are filtered, so debit happens once
🎯
Core idempotence principle: Generate a unique ID for each message and check whether it was processed before doing the operation.

6. 実践:メッセージキューをどう選択するか?

6.1 四大メインストリームメッセージキュー比較

特性RabbitMQKafkaRocketMQRedis Stream
位置付け従来型MQ分散ログストリームECグレードMQ軽量キュー
スループット~1万/秒~100万/秒~10万/秒~5万/秒
レイテンシマイクロ秒級ミリ秒級ミリ秒級ミリ秒級
信頼性高(永続化)高(マルチレプリカ)高(同期フラッシュ)中(AOF)
メッセージリプレイ非対応対応対応対応
トランザクションメッセージ対応(弱)非対応対応(強)非対応
遅延メッセージ対応非対応対応非対応
適用シーン従来型企業アプリログ、ビッグデータEC、金融小規模アプリ

💡 選定アドバイス

決定木:

メッセージキュー選択:

├─ トランザクションメッセージ(分散トランザクション)が必要?
│  ├─ はい → RocketMQ(第一候補)または RabbitMQ
│  └─ いいえ → 続行

├─ 大量ログ/リアルタイムストリーム処理が必要?
│  ├─ はい → Kafka(第一候補)
│  └─ いいえ → 続行

├─ QPS > 1万/秒?
│  ├─ はい → RocketMQ または Kafka
│  └─ いいえ → 続行

├─ 複雑なルーティング(headers マッチなど)が必要?
│  ├─ はい → RabbitMQ
│  └─ いいえ → 続行

├─ 既存の Redis インフラがある?
│  ├─ はい → Redis Stream(クイックスタート)
│  └─ いいえ → RabbitMQ(機能が充実、学習曲線が適度)

7. まとめ:メッセージキュー設計の心構え

7.1 核心原則の振り返り

原則意味実践ポイント
デカップリングサービス間の直接的依存なしメッセージキューで通信、コンシューマー障害はプロデューサーに影響しない
ピークカットトラフィック変動の平滑化メッセージキューを貯水池とし、コンシューマーは一定レートで処理
信頼性メッセージを失わないプロデューサー確認 + Broker永続化 + コンシューマー確認
冪等性重複消費の影響なしビジネスレベルで冪等性を保証(一意キー、ステートマシン)
順序性メッセージ順序保証単一パーティション順序またはコンシューマー側ソート

7.2 設計チェックリスト

メッセージキューを導入する前に、以下の質問を自問しよう:

  • [ ] 本当にメッセージキューが必要か?(単純な非同期はスレッドプールで十分)
  • [ ] メッセージ喪失は許容できるか?(信頼性レベルを決定)
  • [ ] メッセージ重複は業務に影響するか?(冪等性への投資を決定)
  • [ ] メッセージ順序は重要か?(パーティション戦略を決定)
  • [ ] コンシューマーの処理能力は?(キューサイズとアラート閾値を決定)
  • [ ] 消費失敗にどう対処するか?(リトライとデッドレター戦略を決定)

8. 用語クイックリファレンス

用語正式名称説明
MQMessage Queueメッセージキュー。非同期通信のためのミドルウェア。プロデューサーとコンシューマーのデカップリングを実現。
Producer-プロデューサー。メッセージを送信する側。
Consumer-コンシューマー。メッセージを受信し処理する側。
Broker-メッセージブローカー。メッセージを保存・転送するサーバープログラム。
Topic-トピック。メッセージの論理的分類(例:"orders")。
Queue-キュー。メッセージを保存する物理コンテナ。
Partition-パーティション。Kafkaの概念。一つのTopicを複数のPartitionに分割し並行性を向上。
ACKAcknowledgment確認。コンシューマーがメッセージ処理後、Brokerに確認を送る。
Pub/SubPublish/Subscribeパブリッシュ/サブスクライブ。一つのメッセージを複数のコンシューマーが受信できるメッセージパターン。
P2PPoint-to-Pointポイントツーポイント。一つのメッセージを一つのコンシューマーのみが受信できるメッセージパターン。
DLQDead Letter Queueデッドレターキュー。消費不能なメッセージを格納する。
Idempotence-冪等性。複数回実行しても結果が同じであること。
Throughput-スループット。単位時間あたりの処理メッセージ数。
Latency-レイテンシ。メッセージ送信から受信までの時間差。
Persistence-永続化。メッセージをディスクに書き込み、メモリのみに保持しないこと。
Replication-レプリケーション。高可用性のため、メッセージを複数ノードに複製すること。
Transaction Message-トランザクションメッセージ。ローカルトランザクションとメッセージ送信の一貫性を保証する。
Backpressure-バックプレッシャー。コンシューマーが処理しきれない場合、プロデューサーに減速を通知すること。
Offset-オフセット。パーティション内でのコンシューマーの消費位置。
Rebalance-リバランス。コンシューマーグループのメンバー変更時、パーティションを再割り当てすること。