1. はじめに
アクティブMQ:
ActiveMQ は、Java 言語に基づいて Apache Software Foundation によって開発されたオープン ソースのメッセージ ブローカーであり、JMS を実装しています。
ラビットMQ:
RabbitMQ は、アドバンスト メッセージ キュー プロトコル (AMQP) を実装するオープン ソースのメッセージ ブローカー ソフトウェア (メッセージ指向ミドルウェアとも呼ばれます) です。RabbitMQ サーバーは Erlang 言語で記述されており、クラスタリングとフェイルオーバーは Open Telecommunications Platform フレームワーク上に構築されています。すべての主要なプログラミング言語には、プロキシ インターフェイスと通信するクライアント ライブラリがあります。RabbitMQ は、複数のメッセージング プロトコル、配信確認、その他の機能をサポートしています。
カフカ:
Apache Kafka は、Apache Software Foundation によって開発され、Scala で書かれたオープン ソースのメッセージング システム プロジェクトです。
Kafka はもともと LinkedIn によって開発され、2011 年初頭にオープンソース化されました。2012 年 10 月に Apache Incubator を卒業。
このプロジェクトの目標は、リアルタイム データを処理するための、高スループット、低遅延の統合プラットフォームを提供することです。Kafka は、分散型、パーティション化された、マルチレプリカのログ送信サービスです。独自の設計を通じてメッセージング システムの機能を提供します。
ロケットMQ:
Apache RocketMQ は、低遅延、強力な一貫性、高いパフォーマンスと信頼性、テラスケールの容量、柔軟な拡張性を備えた分散メッセージングおよびストリーミング プラットフォームです。Kafka からデザインのアイデアを借用していますが、Kafka のコピーではありません。JMSに基づいて実装されています。
パルサー:
Apache Pulsar は、Apache Software Foundation の最上位プロジェクトです。メッセージング、ストレージ、軽量関数コンピューティングを統合する次世代のクラウドネイティブ分散メッセージ フロー プラットフォームであり、コンピューティング アーキテクチャとストレージ アーキテクチャを分離して設計されています。マルチテナンシー、永続ストレージ、およびマルチマシンルームのクロスリージョンデータレプリケーションをサポートし、強力な一貫性、高スループット、低遅延、高スケーラビリティなどのストリーミング データ ストレージ特性を備え、リアルタイム メッセージとみなされます。クラウドネイティブ時代のストリーミング配信とストレージの最適解を計算します。
より詳細な概要については、ドキュメント「RabbitMQ、RocketMQ、Kafka、および Pulsar メッセージ キューの比較」を参照してください。
2. 機能・性能比較
- 消費プッシュプルモデル
クライアント コンシューマがメッセージを取得する方法では、Kafka と RocketMQ はロング ポーリングを通じてメッセージをプルします。Pull、RabbitMQ、Pulsar、NSQ はすべて Push を使用します。
プル タイプのメッセージ キューは、高スループットのシナリオにより適しており、コンシューマが独自のフローを制御し、実際の消費能力に基づいてメッセージを取得できるようになります。プッシュ型メッセージ キューはリアルタイム パフォーマンスに優れていますが、優れたフロー制御戦略 (バックプレッシャー) が必要であり、コンシューマの消費容量が不十分な場合は、コンシューマを圧迫しないようにプッシュ消費の数を減らすことができます。
- 遅延キュー
メッセージの遅延配信: メッセージが生成されてメッセージ キューに配信されるとき、一部のビジネス シナリオでは、コンシューマがメッセージをすぐに受信するのではなく、コンシューマが消費するメッセージを取得できるようになるまで、特定の期間待機する必要があります。遅延キューは通常、メッセージベースの遅延とキューベースの遅延の 2 つのタイプに分類されます。メッセージベースの遅延とは、メッセージごとに異なる遅延時間を設定することを指します。新しいメッセージがキューに入ると、メッセージは遅延時間に従って並べ替えられます。当然、これはパフォーマンスに大きな影響を与えます。別の種類のキューベースの遅延は、異なる遅延レベルを持つキューを設定することを指します。キュー内の各メッセージの遅延時間は同じであるため、遅延時間に基づいた並べ替えによって引き起こされるパフォーマンスの損失を回避できます。特定のスキャン戦略を通じて、タイムアウトしたメッセージは配信できます。
遅延メッセージの使用シナリオには、異常検出の再試行、注文タイムアウトのキャンセルなどが含まれます。次に例を示します。
- サービス要求が異常な場合は、異常な要求を別のキューに入れて 5 分後に再試行する必要があります。
- ユーザーは商品を購入しましたが、まだ支払っていません。ユーザーには定期的に支払うよう通知する必要があり、タイムアウトが経過すると注文はクローズされます。
- 面接や会議の予約の場合は、面接や会議が始まる 30 分前に再度通知する通知を送信します。
Kafka は遅延メッセージをサポートしていません。Pulsar は、第 2 レベルの遅延メッセージをサポートしています。すべての遅延配信メッセージは、対応するインデックスを使用して遅延メッセージ トラッカーによって記録されます。コンシューマが消費すると、最初に遅延メッセージ トラッカーにアクセスして、期限切れのメッセージがあるかどうかを確認します。有効期限切れのメッセージがある場合は、Tracker から対応するインデックスを取り出し、該当するメッセージを見つけて消費し、期限切れのメッセージがない場合は、通常のメッセージを直接消費します。長期遅延メッセージの場合、メッセージはディスクに保存され、遅延間隔が近づくとメモリにロードされます。
RocketMQ オープン ソース バージョンの遅延メッセージは内部トピックに一時的に保存され、任意の時間精度をサポートせず、タイミング 5 秒、10 秒、1 分などの特定のレベルをサポートします。
RabbitMQ には、rabbitmq_layed_message_exchange プラグインをインストールする必要があります。
NSQ は、遅延メッセージをメモリ内の優先キューを通じて保存し、第 2 レベルの精度と最大 2 時間の遅延をサポートします。
- 配信不能キュー
何らかの理由により、メッセージが正しく配信されない場合、メッセージは理由もなく破棄されないように、通常、特別な役割を持つキューに入れられます。このキューは一般にデッドレターキューと呼ばれます。これに対応して、「ロールバックキュー」という概念もあり、コンシューマが消費する際に例外が発生した場合、消費は確認(Ack)されず、ロールバック操作後は常にメッセージが利用できなくなることを想定してください。メッセージはキューの先頭に配置され、継続的に処理されてロールバックされるため、キューが無限ループに陥ります。この問題を解決するには、キューごとにロールバック キューを設定し、デッド レター キューと合わせて例外処理のメカニズムを保証します。実際の状況では、ロールバック キューの役割は、デッド レター キューとリトライ キューによって果たされます。
Kafka にはデッド レター キューがなく、Offset を通じて現在の消費量のオフセットを記録します。
Pulsar には再試行メカニズムがあります。一部のメッセージがコンシューマーによって初めて消費され、正常な応答を受信しない場合、メッセージは再試行トピックに入ります。再試行が特定の回数に達すると、再試行を停止して、デッドレタートピック中。
RocketMQ は DLQ を使用して、すべての消費失敗メッセージを記録します。
RabbitMQ は、遅延キューに似た形式でデッドレター キューを実装します。
NSQ にはデッドレターキューがありません。
- 優先キュー
優先キューは先入れ先出しキューとは異なり、優先度の高いメッセージには最初に消費される特権があり、さまざまなメッセージ レベルのダウンストリーム保証を提供できます。ただし、この優先順位には前提条件も必要です。コンシューマの消費速度がプロデューサの速度よりも大きく、メッセージ ミドルウェア サーバー (一般に単にブローカーと呼ばれます) にメッセージの蓄積がない場合、送信されるメッセージの優先順位を設定する必要があります。メッセージはプロデューサーが送信するとすぐにコンシューマーによって消費されるため、実質的な意味はありません。つまり、ブローカーには最大でも 1 つのメッセージがあり、単一のメッセージの優先度は無意味です。
Kafka、RocketMQ、Pulsar、および NSQ は優先キューをサポートしていません。メッセージの優先順位は別のキューを通じて実現できます。
RabbitMQ は優先メッセージをサポートします。
- メッセージのトレースバック
通常、メッセージは消費が完了した後に処理され、メッセージは消費できなくなります。メッセージ バックトラッキングはその逆で、メッセージが消費された後も、以前に消費されたメッセージを引き続き消費できることを意味します。メッセージの場合、よくある問題は「メッセージの消失」です。本当にメッセージが消失したのは、メッセージミドルウェアの欠陥によるものなのか、ユーザーの誤用によるものなのかを追跡することは一般に困難です。メッセージミドルウェア自体にメッセージトレースバック機能がある場合、メッセージミドルウェア自体にメッセージトレースバック機能がある場合、バックトレース消費を通じて「失われた」メッセージを再現し、問題の原因を見つけることができます。メッセージ バックトラッキングの役割は、インデックスの回復やローカル キャッシュの再構築など、これをはるかに超えており、一部のビジネス補償ソリューションはバックトラッキングを通じて実装することもできます。
Kafka はメッセージ バックトラッキングをサポートしており、タイムスタンプまたは指定されたオフセットに基づいてコンシューマーのオフセットをリセットして、繰り返し使用できるようにします。
Pulsar は、時間によるメッセージのバックトラッキングをサポートしています。
RocketMQ は時間によるバックトラッキングをサポートしており、実装原則は Kafka と一致しています。
RabbitMQ はバックトラッキングをサポートしていません。メッセージは確認用にマークされると、削除用にマークされます。
NSQ の一般メッセージは追跡できませんが、nsq_to_file ツールを使用してメッセージをファイルに書き込み、そのファイルからメッセージを再生できます。
- メッセージの永続性
トラフィックのピークカットはメッセージ ミドルウェアの非常に重要な機能であり、この機能は実際にそのメッセージ蓄積機能の恩恵を受けています。ある意味、メッセージミドルウェアにメッセージを蓄積する機能がなければ、メッセージミドルウェアとして適格とは言えません。メッセージの蓄積は、メモリ蓄積とディスク蓄積に分けられます。一般に、ディスクの容量はメモリの容量よりもはるかに大きくなりますが、ディスク型スタッキングの場合、スタッキング容量はディスク全体のサイズになります。別の観点から見ると、メッセージの蓄積は、メッセージ ミドルウェアに冗長ストレージ機能も提供します。
Kafka と RocketMQ は永続化のためにメッセージをディスク ファイルに直接フラッシュし、すべてのメッセージはディスクに保存されます。ディスク容量が十分であれば、無制限にメッセージを蓄積できます。
RabbitMQ は典型的なメモリ内スタックですが、これは絶対的ではありません。特定の条件がトリガーされた後、メモリ内のメッセージをディスクにページングするページング アクションが発生します (ページング アクションはスループットに影響します)。または、遅延キューを使用して、メモリ内のメッセージをディスクにページングします。メッセージはディスクに直接保存されます。
Pulsar メッセージは BookKeeper ストレージ クラスタに保存され、ディスク ファイルでもあります。
NSQ は、nsq_to_file ツールを通じてメッセージをファイルに書き込みます。
- メッセージ確認の仕組み
メッセージ キューは、消費の進行状況を管理し、コンシューマがメッセージを正常に処理したかどうかを確認する必要があります。プッシュ メソッドを使用するメッセージ キュー コンポーネントは、多くの場合、単一のメッセージを確認します。未確認のメッセージについては、遅延再配信または配信不能キューへのエントリが実行されます。 。
Kafka は Offset を通じてメッセージを確認します。
RocketMQ, like Kafka, also submits Offset. 違いは、コンシューマが、消費に失敗したメッセージをメッセージ消費失敗としてマークできることです。ブローカーは配信を再試行します。複数の消費失敗が蓄積すると、それらはデッド レター キューに配信されます。
RabbitMQ は NSQ に似ており、コンシューマは 1 つのメッセージを確認します。確認しない場合は、メッセージはキューに戻されて次の配信を待ちます。
Pulsar は特殊なカーソル管理を使用します。累積的な確認には Kafka と同じ効果があり、単一または選択的な確認が提供されます。
- メッセージTTL
メッセージ TTL は、メッセージの生存時間を示します。メッセージの送信後、TTL 時間内にメッセージを消費するコンシューマーがいない場合、メッセージ キューはメッセージを削除するか、デッドレター キューに入れます。
Kafka は、設定された保存期間に基づいてメッセージを削除します。メッセージが消費されず、期限切れ後に削除された可能性があります。TTLはサポートされていません。
Pulsar は TTL をサポートしており、構成された TTL 期間内にメッセージがどのコンシューマーによっても消費されない場合、メッセージは自動的に確認済みとしてマークされます。メッセージ保存期間とメッセージ TTL の違いは、メッセージ保存期間は確認済みとしてマークされ、削除済みに設定されたメッセージに適用されるのに対し、TTL は確認済みではないメッセージに適用されることです。パルサーの TTL は、上の凡例で説明されています。たとえば、サブスクリプション B にアクティブなコンシューマーがいない場合、実際にメッセージを読んだコンシューマーがいない場合でも、構成された TTL 期間が経過すると、メッセージ M10 は自動的に確認済みとしてマークされます。
RocketMQ にはメッセージ TTL に関する情報が比較的少ないですが、インターフェイスはそれをサポートしているようです。
RabbitMQ には 2 つの方法があり、1 つはキュー宣言時にキューのプロパティに設定する方法で、キュー全体のメッセージの有効期間は同じになります。メッセージの送信時にメッセージの属性を設定し、メッセージごとに異なる TTL を設定することもできます。
NSQ はまだサポートされていないようで、オープン状態の機能リクエストの発行があります。
- マルチテナントの分離
マルチテナントとは、単一のソフトウェア インスタンスを通じて複数のテナントにサービスを提供する機能を指します。テナントは、システムに対して同じ「ビュー」を持つユーザーのグループです。マルチテナントをサポートしていないシステムでは、多くの場合、物理的な分離を実現するために、異なるユーザーまたは異なるクラスターに対して複数のメッセージ キュー インスタンスを作成する必要があり、これにより、運用コストと保守コストが高くなります。エンタープライズ レベルのメッセージング システムとして、Pulsar のマルチテナント機能は次のニーズを満たすように設計されています。
- 厳しい SLA をスムーズに満たせるようにします。
- 異なるテナント間の分離を確保します。
- リソース使用率にクォータを適用します。
- テナントごとおよびシステムレベルのセキュリティを提供します。
- 可能な限り低コストの運用保守とシンプルな管理を確保します。
Pulsar は、次の方法で上記のニーズを満たします。
- 各テナントの認証、認可、ACL (アクセス コントロール リスト) により、必要なセキュリティを確保します。
- テナントごとにストレージ クォータを強制します。
すべての分離メカニズムはポリシーの形式で定義されており、運用中に変更できるため、運用と保守のコストが削減され、管理が簡素化されます。
- メッセージシーケンス
メッセージの順序性とは、メッセージが順序どおりであることを保証することを指します。メッセージの消費順序は、生成の順序と一致します。
Kafka は、パーティション内のメッセージが順序付けされていることを保証します。
Pulsar は 2 つの消費モードをサポートしています。排他的サブスクリプション ストリーミング モードはメッセージの順序のみを保証し、共有サブスクリプション キュー モデルは順序を保証しません。
RocketMQ はロックを使用して、キューに同時に消費するコンシューマ スレッドが 1 つだけあることを確認し、メッセージの順序性を確保する必要があります。
RabbitMQ には厳格なシーケンシャル条件があり、シングル スレッドの送信とシングル スレッドの消費が必要であり、遅延キューや優先キューなどの高度な機能は使用しません。
NSQ は、golang 独自の case/select を使用してメッセージ配布を実装しますが、順序付けの保証は提供されず、特徴的なメッセージとコンシューマーの照合ができず、メッセージの順序付けも実現できません。
- メッセージクエリ
実際の開発では、特定の MessageKey/ID を介して MQ の特定のメッセージをクエリするなど、MQ のメッセージの内容を確認する必要があることがよくあります。または、メッセージのリンクを追跡して、メッセージの送信元と送信先を知ることができるため、トラブルシューティングを迅速に行って問題を特定することができます。
Kafka ストレージ層は分散コミット ログの形式で実装され、各書き込み操作はログの末尾に順次追加されます。読み取りもシーケンシャル読み取りです。検索機能はサポートされていません。
Pulsar は、メッセージ ID を通じて特定のメッセージのメッセージ内容、メッセージ パラメーター、メッセージ トラジェクトリをクエリできます。
RocketMQ は、メッセージ キー、一意のキー、およびメッセージ ID によるメッセージのクエリをサポートしています。
RabbitMQ はインデックスベースのストレージ システムを使用します。これらはデータをツリー構造に保存し、個々のメッセージを確認するために必要な素早いアクセスを提供します。RabbitMQ メッセージは確認後に削除されるため、未確認のメッセージのみをクエリできます
NSQ 自体はメッセージの永続化とメッセージの取得をサポートしていませんが、nsq_to_http などのツールを使用して、インデックス付けをサポートするストレージにメッセージを書き込むことができます。
- 消費パターン
Kafka には 2 つの消費モードがあり、最終的には 1 つのコンシューマのみがパーティションを消費するようになります。
- Subscribe方式:トピックパーティション数やコンシューマー数が変化した場合にリバランスが行われますが、リバランスリスナーを登録することで、リスナーを登録せずにオフセットを手動で管理することができ、Kafkaが自動で管理します。
- 割り当て方法: コンシューマをパーティションに手動でマップします。Kafka はリバンランスを実行しません。
Pulsar には次の 4 つの消費モードがあります. 排他モードと災害復旧モードは Kafka に似ています. これらはストリーム モデルです. 各パーティションには 1 つのコンシューマ消費のみがあり、これによりメッセージの順序性が保証されます。共有モードとキー共有モードはキュー モデルであり、複数のコンシューマを使用すると消費速度は向上しますが、順序性は保証できません。
- 排他的排他モード (デフォルト モード): サブスクリプションは 1 つのコンシューマにのみ関連付けることができます。このコンシューマのみがトピックからすべてのメッセージを受信できます。コンシューマが失敗すると、コンシューマは停止します。
- 災害復旧モード (フェイルオーバー): 複数のコンシューマが存在する場合、コンシューマは辞書順に並べ替えられ、最初のコンシューマがメッセージを受信する唯一のコンシューマとして初期化されます。最初のコンシューマが切断されると、すべてのメッセージ (未確認のメッセージとその後受信するメッセージ) がキュー内の次のコンシューマに配布されます。
- 共有モード (共有): メッセージは、ラウンド ロビン ポーリング メカニズム (カスタマイズも可能) を通じてさまざまなコンシューマに配信され、各メッセージは 1 つのコンシューマにのみ配信されます。コンシューマが切断されると、そのコンシューマに送信された未確認メッセージはすべて再スケジュールされ、他の生き残っているコンシューマに配布されます。
- KEY共有モード(Key_Shared): コンシューマが複数ある場合、キーに応じてメッセージが配信され、同じキーを持つメッセージは同じコンシューマにのみ配信されます。
RocketMQ には、BROADCASTING ブロードキャスト モードと CLUSTERING クラスター モードという 2 つの消費モードがあります。
ブロードキャスト消費とは、メッセージが複数のコンシューマによって消費されることを指します。これらのコンシューマが同じ ConsumerGroup に属している場合でも、メッセージは ConsumerGroup 内の各 Consumer によって 1 回消費されます。ブロードキャスト消費における ConsumerGroup の概念は、次の点で無意味であると考えられます。メッセージ部門。
クラスター消費モード: ConsumerGroup 内のコンシューマー インスタンスは、消費されたメッセージを均等に共有します。たとえば、トピックに 9 つのメッセージがあり、ConsumerGroup の 1 つに 3 つのインスタンス (おそらく 3 つのプロセスまたは 3 つのマシン) がある場合、各インスタンスはメッセージの一部のみを消費し、消費されたメッセージは他のインスタンスによって消費されません。
RabbitMQ と NSQ の消費は似ており、Pulsar 共有モードに似ています。キューの形式で、コンシューマ グループ内のコンシューマの数を増やすと、消費速度が向上します。
- メッセージの信頼性
メッセージ損失は、メッセージ ミドルウェアを使用するときに直面する一般的な問題ですが、その背後にあるメッセージの信頼性も、メッセージ ミドルウェアの品質を測る重要な要素です。特に金融決済の分野では、メッセージの信頼性が特に重要です。たとえば、サービスに障害が発生した場合、プロデューサによって正常に生成されたメッセージの一部が高可用性スイッチング中に失われるのでしょうか? 同期フラッシュはコンポーネントの信頼性を高める効果的な方法であり、メッセージ ミドルウェアも例外ではありません。Kafka と RabbitMQ は両方とも同期フラッシュをサポートできますが、ほとんどの場合、コンポーネントの信頼性は同期フラッシュによって決定されるべきではありません。パフォーマンスを非常に消費する操作を使用してそれを保証するために、マルチコピー メカニズムが使用されます。
Kafka は、request.required.acks パラメーターを構成することで信頼性レベルを設定できます。このパラメーターは、タスクによってメッセージが正常に送信される前に、受信の成功を確認するために必要なメッセージのコピーの数を示します。
- request.required.acks=-1 (完全同期確認、強力な信頼性保証)
- request.required.acks=1 (リーダーが受信を確認、デフォルト)
- request.required.acks=0 (確認なし、ただし高スループット)
Pulsar には、Ack Quorum Size (Qa) と呼ばれる、Kafka に似た概念があります。Qa は、各書き込みリクエストが送信された後、応答によって確認する必要がある Bookies の数です。値が大きいほど、Ack Quorum Size (Qa) を確認するのに時間がかかります。書き込み成功 その値 上限はコピー数 Qw です。一貫性を確保するには、Qa は (Qw+1)/2 以上である必要があります。つまり、データのセキュリティを確保するには、Qa の下限は (Qw+1)/2 です。
RocketMQ は Kafka に似ています。
RabbitMQ は、ミラー化されたリング キューを通じて複数のコピーと強力な一貫性セマンティクスを実装するマスター/スレーブ アーキテクチャです。複数のコピーを使用すると、マスター ノードが異常にダウンした後、スレーブを新しいマスターとして昇格させ、可用性を確保するためのサービスを提供し続けることができます。
NSQ は go-diskqueue コンポーネントを通じてメッセージをローカル ファイルに保存し、mem-queue-size パラメータを通じてメモリ内のキュー サイズを制御します。mem-queue-size=0 の場合、各メッセージはディスクに保存され、そこにノードの再起動を心配する必要はありませんが、結果としてメッセージが失われます。ただし、ローカルディスクに保存されているため、ノードがオフラインになるとノードディスクに蓄積されたメッセージは失われます。