RabbitMQが詰まった夜: マイクロサービスにおけるKafka移行と5万TPSの教訓

ブラックフライデーのセール開始からわずか10分、注文処理マイクロサービスのアラートが鳴り止まなくなりました。RabbitMQのキュー深度(Queue Depth)が限界を突破し、コンシューマーがメッセージを捌ききれずにタイムアウトが多発していたのです。MSA環境において非同期通信は生命線ですが、「使い慣れているから」という理由だけでメッセージブローカーを選ぶと、こうしたスケーラビリティの壁に激突します。本稿では、私たちが直面したRabbitMQの限界と、Kafkaへ移行すべき境界線について、実戦経験に基づき解説します。

Deep Dive: アーキテクチャの決定的違い

「どちらもメッセージを運ぶ」という点では同じですが、内部構造は水と油ほど異なります。ここを誤解していると、運用フェーズで必ず痛い目を見ます。

基本思想の違い
RabbitMQは「スマートブローカー、ダムコンシューマー(Smart Broker, Dumb Consumer)」です。ブローカーがルーティングや状態管理の責任を持ちます。
対してKafkaは「ダムブローカー、スマートコンシューマー(Dumb Broker, Smart Consumer)」です。単なるログストレージとして振る舞い、消費状態(オフセット)はクライアントが管理します。

RabbitMQは、複雑なルーティング(Topic Exchange, Header Exchange)が必要な場合や、メッセージごとのACK管理、優先順位付けが必要なタスクキューとして極めて優秀です。しかし、メッセージが消費されると消える設計のため、過去のイベントを再生(Replay)することはできません。

一方、Kafkaは分散コミットログです。ディスクへのシーケンシャル書き込みに特化しており、永続性が高く、コンシューマーが増えてもブローカーの負荷はほとんど変わりません。これが、大量のイベントストリーミング処理でKafkaが選ばれる理由です。また、Kafkaの設定ファイルやスキーマレジストリの定義は、多くの場合gitリポジトリで管理され(GitOps)、変更履歴の追跡やロールバックが容易になるよう運用されます。

パフォーマンスの罠
RabbitMQはメモリ上で動作することを前提としています。キューが溢れてディスクへのスワップが発生し始めると、スループットは劇的に低下します。

The Solution: ユースケース別実装パターン

「どちらが優れているか」ではなく、「どのトラフィック特性に合致するか」で判断します。以下に、それぞれの強みを活かした設定例を示します。

1. RabbitMQ: 確実な配送を重視する注文処理

RabbitMQはメッセージの到達保証(At-least-once)と複雑なルーティングが得意です。以下は、Spring BootでのPublisher Confirm設定例です。ここでは信頼性を最優先しています。

2. Kafka: 超高スループットのログ収集・分析

Kafkaはバッチ処理と圧縮を駆使して、ネットワークI/Oを極限まで減らします。以下のProducer設定は、レイテンシを数ミリ秒犠牲にして、スループットを最大化する「高負荷対策」の設定です。

// Kafka Producer Configuration (Java)
// High Throughput Optimization
Properties props = new Properties();
props.put("bootstrap.servers", "broker1:9092,broker2:9092");

// 1. バッチサイズを増やす
// デフォルト16KB -> 64KB。一度に送信するバイト数を増やし、ネットワーク往復回数を減らす
props.put("batch.size", 65536);

// 2. 待機時間 (Linger)
// 即時送信せず、5ms待ってバッチを埋める。CPU負荷低減と圧縮効率向上に寄与
props.put("linger.ms", 5);

// 3. 圧縮の有効化
// snappyはCPU負荷と圧縮率のバランスが良い。帯域幅の節約に必須
props.put("compression.type", "snappy");

// 4. ACK設定
// "all"は堅牢だが遅い。ログ収集なら"1" (Leaderのみ) で十分な場合が多い
props.put("acks", "1"); 

KafkaProducer<String, String> producer = new KafkaProducer<>(props);
注意: linger.ms を大きくしすぎるとレイテンシが悪化します。また、acks=1 はリーダー障害時にデータロストのリスクがあるため、決済データなどには絶対に使用しないでください。

性能と特性の比較マトリクス

意思決定のための最終チェックリストです。

特性 RabbitMQ Apache Kafka
主な用途 複雑なルーティング、タスクキュー イベントストリーミング、ログ集約
スループット 4k - 10k msg/sec (構成による) 100k - 1M+ msg/sec
メッセージ永続性 消費されると削除 (基本) 設定期間保持 (リプレイ可能)
スケーリング 垂直方向 (Vertical) 推奨 水平方向 (Horizontal) が容易
プロトコル AMQP, MQTT, STOMP TCP (Binary Protocol)

Conclusion

「RabbitMQは遅い」というのは誤りです。適切なユースケース(複雑なルーティングが必要な少〜中規模トラフィック)では、Kafkaよりも運用コストが低く、柔軟性に富んでいます。しかし、秒間数万件を超えるイベントデータや、コンシューマーが過去のデータに遡って処理を行う必要がある場合、Kafka以外の選択肢はほぼありません。

私たちのプロジェクトでは、決済トランザクション管理にはRabbitMQを残し、クリックストリームや在庫更新イベントにはKafkaを採用するハイブリッド構成に落ち着きました。単一のツールですべてを解決しようとせず、データの性質(フローか、ストックか)を見極めてアーキテクチャを決定してください。

Post a Comment