大規模で複雑な分散システムにおいて、サービス間の通信を非同期で行うことは、システムの疎結合化、耐障害性の向上、および負荷の平準化のために不可欠です。これを実現するのが、メッセージングシステム(メッセージキューやストリーム処理)です。
この章では、代表的なメッセージングシステムである RabbitMQ と Apache Kafka を比較し、それぞれの役割と、エキスパートエンジニアが知るべき設計上の原則について解説します。
1. メッセージングシステムの必要性
メッセージングシステムは、主に以下の目的で利用されます。
非同期処理: ユーザーからのリクエストに対して即座に応答を返す必要のない、時間のかかる処理(例: メール送信、画像処理、レポート生成)をバックグラウンドで実行し、フロントエンドの応答速度を向上させます。
疎結合化: サービス間の直接的な依存関係を断ち切ります。サービスAはサービスBの存在を知らなくても、メッセージブローカーを介してデータをやり取りできます。
負荷の平準化(バッファリング): 突然の大規模なトラフィックをメッセージブローカーが一時的に受け止め、コンシューマ(処理側)が処理能力に応じてメッセージを消費することで、バックエンドサービスの過負荷による障害を防ぎます。
2. メッセージキュー (Queue) の利用:RabbitMQ
メッセージキューは、メッセージを順序立てて貯蔵し、一度だけコンシューマに配信することを目的とした、伝統的なメッセージングパターンを実装しています。代表的な製品は RabbitMQ です。
A. 基本的な仕組みと特性
キュー: メッセージが保存される領域です。一般に**先入れ先出し(FIFO)**でメッセージが消費されます。
ブローカー中心: メッセージのルーティング、永続化、配信ステータスの追跡などをすべてブローカー(RabbitMQサーバー)が行います。
プッシュ型配信: メッセージがキューに到着すると、ブローカーがコンシューマに**プッシュ(送信)**します。
メッセージの削除: コンシューマがメッセージを正常に処理し終えたことをブローカーに通知(ACK)すると、メッセージはキューから削除されます。
ユースケース: 非同期タスクの実行、通知メールの送信、処理順序の厳密性が求められる作業。
B. 特徴的な機能:ルーティング
RabbitMQは、メッセージを直接キューに入れるのではなく、Exchangeという機構を介してルーティングルールに基づき、メッセージを適切なキューに振り分けることができます。これにより、柔軟なメッセージの配信パターン(ダイレクト、トピック、ファンアウトなど)を実現します。
3. ストリーム処理 (Streaming) の利用:Apache Kafka
ストリーム処理は、メッセージキューの概念を拡張し、メッセージを「永続的なログ」として扱い、何度でも読み取り可能な、高スループットな分散ログシステムです。代表的な製品は Apache Kafka です。
A. 基本的な仕組みと特性
トピックとパーティション: メッセージはトピックと呼ばれるカテゴリに格納され、トピックは複数のパーティションに分割されて複数のブローカー(Kafkaサーバー)に分散されます。これにより高い並列処理とスケーラビリティを実現します。
コンシューマ中心: ブローカーはメッセージを削除せず、コンシューマは**自分がどこまで読んだか(オフセット)を管理し、メッセージをプル(取得)**します。
メッセージの永続性: メッセージは一定期間(または一定サイズ)削除されずに保存されます。これにより、新しいコンシューマが過去のメッセージを読み直すことや、障害が発生したコンシューマが途中から再開することが可能です。
ユースケース: リアルタイムデータパイプライン、ログ収集、イベントソーシング、ユーザーアクティビティ追跡。
B. 特徴的な機能:イベントソーシング
Kafkaはメッセージを削除しない特性から、システム内で発生したすべての事象をイベントとして永続的なログ(ストリーム)に記録するイベントソーシングという設計パターンを可能にします。これにより、システムの現在の状態を、過去のすべてのイベントを再生することで再現できます。
4. 適切なメッセージングシステムの選択
エキスパートエンジニアは、プロジェクトの要件に応じて適切なシステムを選択する必要があります。
RabbitMQが適しているケース(メッセージキュー):
タスクキュー: 実行が必要なタスクを確実に一度だけ実行したい場合。
処理順序の厳密性: キュー内のメッセージの順序が重要である場合。
シンプルな非同期処理: メッセージの複雑な再利用や長期保存が必要ない場合。
Kafkaが適しているケース(ストリーム処理):
高スループット: 大量のデータをリアルタイムで処理・転送したい場合。
データ永続性: 過去のデータを複数のアプリケーションで再利用したり、障害時に再生したりする必要がある場合。
イベントソーシング: すべてのシステム変更をイベントログとして記録したい場合。
メッセージングシステムの導入は、システムの可用性とスケーラビリティを飛躍的に向上させますが、ネットワーク遅延の管理や、非同期処理に伴う結果整合性への対応(前章のSagaパターンなど)が課題となります。