📝ノート💻テック

Kafka vs RabbitMQ

Tony Duong

Tony Duong

6月 11, 20261

他の言語:🇫🇷🇬🇧
#system-design#kafka#rabbitmq#message-queue#streaming#distributed-systems#interview
Kafka vs RabbitMQ

Kafka と RabbitMQ は相互に置き換え可能なものではなく、間違ったほうを選ぶと後で大きな作り直しが発生しかねません。しかし、この2つは同じ根本的な問題を解決するために存在しています。あるサービスが別のサービスを直接呼び出すとき(注文サービス → 在庫サービスへ HTTP で呼び出す)、呼び出される側が遅かったりダウンしたりした瞬間に、呼び出す側は待たされ、タイムアウトし、リクエストを取りこぼします。メッセージキューはサービスの間にバッファを追加します。プロデューサーはメッセージを投げてすぐに戻り、コンシューマーは準備ができたタイミングで処理します。フラッシュセールのスパイク時には、キューが負荷を吸収し、下流のサービスが自分のペースで処理を進められるようにしてくれます。

どちらもこの疎結合を提供してくれます。プロデューサー、コンシューマー、その間に立つブローカーという構成です。しかし内部の動作の仕組みは根本的に異なり、それこそが選択の決め手になるべきものです。

RabbitMQ:スマートなブローカーとシンプルなコンシューマー

RabbitMQ は、直感的なキューのメンタルモデルを持つ伝統的なメッセージブローカーです。

  • プロデューサーがブローカーにメッセージを送る。
  • ブローカーが、あなたが設定したルーティングルールを適用して、そのメッセージがどのキューに属するかを判断する。
  • コンシューマーがキューからメッセージを取り出して処理し、**確認応答(ack)**を返す。
  • ack を受け取ると、RabbitMQ はメッセージを削除する。配信に失敗したメッセージはリトライされ、繰り返し失敗すると自動的にデッドレターキューへ移される。

ブローカーが重い処理を引き受け(ルーティング、配信の追跡、リトライ、デッドレター化)、コンシューマーはただ購読し、処理し、ack を返すだけです。これはタスク指向のワークロードにきれいに対応します。メールの送信、決済の処理、画像のリサイズなどです。1つの作業単位が入ってきて、何かがそれを実行し、メッセージは消える。(Kafka では、デッドレターの処理は自分で組み立てることになります。)

Kafka:シンプルなブローカーとスマートなコンシューマー

Kafka は本質的に分散された追記専用ログです。プロデューサーはトピックにメッセージを追記し、それは読まれても消えません。保持設定(retention)に応じて、数時間、数日、数週間、あるいは無期限にログの中に残り続けます。

  • コンシューマーは**オフセット(offset)**と呼ばれる自分自身の位置を追跡します。500番目のメッセージを読んだら → 自分が500番にいることを覚えておく。クラッシュして再起動したら → どこまで読んだかを調べて再開する。
  • 1時間前のものを再処理したい? ただオフセットを巻き戻すだけです。
  • メッセージは**永続的かつ再生可能(replayable)**なので、複数の consumer group が同じストリームをそれぞれ独立に読めます。分析と、リアルタイム通知が同じイベントを消費でき、半年後に立ち上がったサービスが初日からの全履歴を読むこともできます。

つまり、RabbitMQ はメッセージブローカーであり、メッセージはその中を流れていく。Kafka はログであり、メッセージはその中に住み続けるということです。RabbitMQ では消費されたメッセージは消えますが、Kafka ではメッセージは残り続け、いくつものコンシューマーが履歴上の任意の地点からそれを読めます。この1つの違いが、ほぼすべての他のトレードオフを左右します。だからこそ多くのチームが両方を使います。耐久性のあるイベントストリームとして Kafka を、それらのイベントが引き起こす作業を処理するタスクキューとして RabbitMQ を使うのです。

技術的なトレードオフ

順序保証(Ordering)

  • RabbitMQ のキューは厳密に順序づけられており、単一のコンシューマーなら完璧な順序が得られます。スループットのためにコンシューマーを複数追加すると、その順序を手放すことになります。
  • Kafka は各トピックをパーティション(partition)に分割し、順序が保証されるのはパーティション内のみです。パーティションキーが関連するメッセージをまとめてルーティングします(顧客 12345 の注文はすべて同じパーティションへ → 順番どおりに処理される)。これによりエンティティ単位の順序保証と並列性が得られますが、グローバルな順序はありません。
  • トレードオフ:RabbitMQ = 単一コンシューマーによるグローバルな順序保証、Kafka = 並列性を伴うエンティティ単位の順序保証。

スループットとレイテンシ

  • RabbitMQ:約 4,000〜10,000 メッセージ/秒、低負荷時で約 1〜5 ms のレイテンシ。ブローカーはメッセージをプッシュしますが、メッセージごとに多くの処理(配信状態の管理、ack、ルーティング)を行うため、そのオーバーヘッドが積み重なるにつれてスループットは下がります。
  • Kafka:1,000,000 メッセージ/秒以上(約100倍)。ただしコンシューマーがバッチでプルするため、ベースのレイテンシは高め(約 5〜50 ms)です。ブローカーは順次的なログに追記するだけなので、ボリュームが増えてもレイテンシは一定に保たれます。

配信保証(Delivery guarantees)

コンシューマーがメッセージの処理に失敗したとき、そのメッセージを失うか、あるいは再配信する(重複のリスクを負う)かのどちらかになります。

  • at-most-once(最大1回):ブローカーは1回送り、リトライしない。高速だが、メッセージが永久に失われることがある。
  • at-least-once(最低1回):ブローカーは ack されるまでリトライする。データの損失はないが、コンシューマーが同じメッセージを2回見ることがある。両方のシステムがこれをサポートしており、業界標準のデフォルトです。
  • exactly-once(ちょうど1回):Kafka はこれをサポートしますが、聞こえほど広い保証ではありません。入力も出力も同一クラスタ内の Kafka トピックで、Kafka のトランザクションの下にある場合に限られます。データベースに書き込んだ瞬間、外部 API を呼んだ瞬間、あるいはクラスタをまたいだ瞬間に、at-least-once へ逆戻りします。「exactly-once」のためだけに Kafka を選んではいけません。実際には依然として**冪等なコンシューマー(idempotent consumers)**が必要です。

運用の複雑さ

  • RabbitMQ はシンプルです。単一のバイナリ、わかりやすいクラスタリング、組み込みの管理 UI を備えており、いくつかのキューを運用する小さなチームでも扱いやすいです。
  • Kafka はより難しいです。歴史的には Zookeeper が必要でした(新しいバージョンでは代わりに Raft を使用)。加えてパーティションのリバランス、ブローカーの障害、トピックの設定、consumer group の協調などがあります。マネージドサービス(Confluent Cloud、Amazon MSK、Azure Event Hubs)はこの大部分を肩代わりしてくれます。すでにインフラの専門知識がある場合を除き、利用を強く検討すべきです。

どちらをいつ使うか

RabbitMQ を選ぶのは、タスクキューやバックグラウンドジョブ(メール、決済、画像リサイズ。作業が入り、実行され、消える)、コンテンツベースのスマートなルーティング、中規模スケールでの低レイテンシ、そしてシンプルな運用が必要なときです。実例:Instagram は写真アップロードの処理(リサイズ・フィルタリング)を RabbitMQ のワーカー経由で行っています。Reddit はコメントスレッドやカルマに利用しています。

Kafka を選ぶのは、複数のシステムが同じイベントをそれぞれ独立に読む必要があるとき(分析、不正検知、課金、監査ログ)、履歴データの再生(replay)、巨大なスケール(一定のレイテンシで毎秒数百万イベント)、あるいは耐久性のある恒久的なイベント履歴が必要なときです。実例:Netflix は推薦と課金のために1日あたりペタバイト規模を処理しています。Uber はリアルタイムの価格設定と不正検知に利用しています。LinkedIn は Kafka を発明し、フィードとメッセージングをそれで支えています。

重要なポイント

  • スマートなブローカー+シンプルなコンシューマー(RabbitMQ) vs シンプルなブローカー+スマートなコンシューマー(Kafka) — これが根本的な区別です。
  • キュー vs ログ:RabbitMQ は ack で削除し、Kafka は保持してどのコンシューマーでも offset によって再生できる。
  • 順序保証:RabbitMQ はグローバル(単一コンシューマー)、Kafka はパーティション単位(並列)。パーティションキーは意図的に選ぶこと。
  • スループット/レイテンシ:RabbitMQ は約 4k〜10k メッセージ/秒で 1〜5 ms、Kafka は 100万以上/秒で 5〜50 ms。
  • exactly-once を追い求めるな — それは Kafka クラスタ内部に限られる。いずれにせよ冪等なコンシューマーを作ること。
  • ユースケースが限定的なタスクキューなら、シンプルさのために RabbitMQ を選ぶ。耐久性があり再生可能で高スケールなイベントストリームなら Kafka(おそらくマネージド)に寄せる。あるいは両方を使う。

🌐 Claudeによる翻訳

Tony Duong

著者: Tony Duong

デジタル日記。思考、経験、そして人生についての考え。