分散 messaging system, message broker (kafka, rabbitmq を理解する前に基礎)
こんにちはcodeshowです。
今回は分散メッセージングシステムを学習します。
メッセージングシステムでのメッセージとは、複数の関係でやり取りできるデータです。
ここでのデータは、通常バイナリデータです。 jsonやProtocol Buffersなどのシリアライザを使用してデータを送受信します。
メッセージングシステムを中央に置き、一方はpublisher、もう一方は subscriber 関係を結びます。
publisherは、メッセージを生成してメッセージキューに送信するクライアントです。メッセージをキューに送信することをpublishといいます。
subscriberは、メッセージキューからメッセージを受信するクライアントです。メッセージをキューから取得することをconsumeと呼びます。
メッセージはpublisherがpublishし、メッセージングシステムを経て subscriber にメッセージが移動します。
メッセージは常にpublisher、メッセージングシステム、 subscriber で常に一方向に流れます。
ちなみにpublisherの代わりにproducer、 subscriber の代わりにconsumer用語を使用します。
そしてpublisherと subscriber を減らして pub, sub を使用します。
publisherとsubscriberの関係を理解するために、コードを例として説明します。
package main
import "time"
func main() {
c := make(chan string)
go pub(c)
go sub(c)
select {}
}
func sub(c <-chan string) {
for {
message := <-c
println(message)
}
}
func pub(c chan<- string) {
c <- "Hello World 1"
time.Sleep(1 * time.Second)
c <- "Hello World 2"
time.Sleep(1 * time.Second)
c <- "Hello World 3"
time.Sleep(1 * time.Second)
c <- "Hello World 4"
time.Sleep(24 * time.Hour)
}
このコードでは、main関数からstring型のchannelを作成します。
pub 関数は “Hello World” 文字を publishします。
そしてsubはfor無限ループの中でchannelにメッセージが届いたら「Hello World」を出力します。
pub 関数の中では channel に string をpublishして、
sub 関数は channel を通じて文字列をconsumeします。
メッセージをconsumeして処理するモジュールをworkerとも呼びます。
先にpublisher, メッセージングシステム, subscriber の関係を
上記の高言語コードでは、 pub 関数はpublisher、 sub 関数は subscriber として機能します。
そしてこの pub, sub の間にある string channel タイプの c 変数をメッセージングシステムと考えることができます。
高言語のように言語でメッセージングを提供しない場合は、フレームワークによって提供されます。
JavaのSpringFrameworkを例にとると、ApplicationEventタイプのメッセージを発行します。
そして、EventListenerアノテーションを介してpublishたメッセージを購読できます。
この時、メッセージングシステムはスプリングフレームワークが担当することになります。
ちなみに、メッセージとイベントは似ています。
2つの違いは、メッセージングは通常Queueと呼ばれるリポジトリにメッセージを保存しておき、subscriberがすぐに処理せず、後で処理が可能ですが、
イベントは発生した瞬間に購読者に送出され、イベントは破棄されます。
上記のように、メッセージングにはキューと呼ばれるリポジトリがあります。
だからMessage Queueと呼びます。
一般に、メッセージングシステムは、分散環境でメッセージを配信および処理するために作成されています。
したがって、高言語のチャネルやSpringFrameworkのEventListenerは、限られた文脈ではメッセージングシステムではありません。
しかし、前に話したことや後ろに話すことはすべてevent driven architectureに従い、広い意味でメッセージングシステムと見なすことができます。
それでは、今から分散メッセージングシステムで最もよく使われるkafkaとrabbitmqを見てみましょう。
まず、 kafkaとrabbitmqはどちらも分散環境で動作するメッセージングシステムです。
またmessage brokerと呼びます。
分散メッセージングシステムは通常、スケーラビリティ、高可用性、信頼性を提供します。
- スケーラビリティはkafkaと rabbitmq はcluster を設定できます。
これにより、ノード数を増やして水平拡張を行うことができます。
水平方向の拡張によりスループットを増やすことができます。 - 高可用性は、一部のノードがダウンしてもメッセージングシステムが動作できるようにする必要があります。
3.信頼性は、発行されたメッセージを失うべきではなく、サブスクライバにメッセージを重複して送信しないなど、メッセージ配信に対して信頼できる動作をします。
kafkaと rabbitmq は前の分散メッセージシステムとしての条件を満たします。
そしてpublisherは一度に 1 つのメッセージをpublishますが、メッセージングシステムを通じてこのメッセージは複製され、複数のqueueに渡すことができます。
例えば、
kafkaはtopicイラン単位でメッセージを分割します。
そして、このtopicは再びいくつかのpartitionに分割されます。
そして、購読者側はconsumer group を介して 1 つのメッセージを多数のworkerが使用できます。
rabbitmq は exchange とqueueで構成されます。
exchangeは、どのqueueにメッセージを渡すかを決定します。
rabbitmq は direct, fanout, topic, headers この 4 種類の exchange があります。
さまざまなexchangeにメッセージを配信できるだけでなく、exchangeからexchangeにもルーティングができるため
rabbitmqはkafkaと比較してメッセージルーティング設計が非常に柔軟で便利です。
代わりに rabbitmq はqueueであるため、 queueでメッセージをconsumerが dequeue にすると、 queueからそのメッセージが削除されます。
一方、 kafkaは保存されている単位がqueueではなく、 topicとpartitionです。
topicはメッセージを区別する論理的な単位であり、実際に格納される単位はpartitionです。
そしてconsumerがpartitionでメッセージを消費してもqueueのようにメッセージを削除しません。
特定のoffsetを覚えておいて、 offset以降のデータを subscribe します。これは配列に似ています。
この違いで、rabbitmqは1つのqueueに複数の加入者を付けることができますが、 kafkaは1つのpartitionには1つのconsumerグループだけを付けることができます。
2つの違いはリポジトリにも違いがあります。
rabbitmq は主にメモリにkafkaはディスクに保存します。
そのため、 kafkaをデータベースのように永続データストアとして使用します。
これらの動作の違いは、メッセージングシステムの追求に応じてメッセージングシステムの設計に反映されています。
rabbit mqはmessage queueing に目的があります。
そのため、 kafkaと比較してメッセージキューへのルーティングとqueue生成の削除について非常に柔軟です。
kafkaは rabbitmq に比べて大規模なメッセージ処理に目的があります。
そのため、rabbitmqに比べて大量のバッチ作業に優れた性能を持っています。
以上、分散メッセージングシステムを見て、rabbitmqとkafkaについて簡単に見ました。
今後のコードで、 kafkaとrabbitmqについてさらに詳しく見てみましょう。
最後に、私たちがメッセージングシステムを使用する理由を5つにまとめました。
- 通信: publisherと subscriber の間でデータを渡すことができます。これは他の言語、プラットフォーム、異機種間の制約から自由になります。
2.非同期:同期通信と比較して非同期通信は、手続き型通信と比較してパフォーマンスを向上させることができます。
3.高可用性:分散メッセージングシステムでは、一部のメッセージングシステムがダウンしてもパフォーマンスは低下しますが、正常に動作します。 - 再試行: workerがダウンしてもメッセージはqueueに残るため、 workerが再び生き返る場合は、以前に失敗した作業の後に続くことができます。リアルタイム性は低下しても、データに対する整合性を信頼できるようになります。
5.疎結合:直接呼び出しではなくメッセージングシステムを介した間接呼び出しにより、publisher側はメッセージ発行後にすべてのビジネスロジックを知る必要はありません。発行までのみpublisherの役割です。その後、メッセージングシステムを介してこのメッセージは購読者に配信されます。今、メッセージの処理の責任は購読者です。 publisherの直接呼び出しではなく間接呼び出しによって得られる緩い結合により、当社のソフトウェアは柔軟性とスケーラビリティを高めることができます。
サブスクリプションといいね!通知設定は、コンテンツ制作者に多くの役に立ちます。
ありがとうございます。