Re:Architect

今日よりも一歩進んだ世界を実現するためのアーキテクチャを考えます

はじめからの分散メッセージングシステム  ~Part1.メッセージング基盤とは~

分散メッセージング基盤と聞いて何を思い浮かべるでしょうか。
最近流行りのchatGPTに尋ねてみたところ、以下の回答が返ってきました。

分散メッセージング基盤(Distributed Messaging Infrastructure)とは、複数のコンピューターやデバイス間で情報をやり取りするためのシステムのことを指します。 分散メッセージング基盤は、分散型システムを構築する際に使用されることが多く、スケーラビリティや可用性を高めることができます。また、分散メッセージング基盤は、リアルタイムでの情報交換やデータのやり取りが必要なアプリケーションでも使用されることがあります。例えば、複数のデバイスで同期して動作するゲームや、IoT(Internet of Things)デバイスでの情報収集などです。

上記に記載の通り、データのやり取りが必要なアプリケーションで使われるような技術です。 Apache KafkaやAmazon Kinesisなんかは聞いたことがある人もいるのではないでしょうか。
本記事では単純なノード間のやり取りからはじめて、メッセージング基盤、および"分散"メッセージング基盤まで解説することを目指します。最後には主要な製品の解説も入れるつもりです。

目次

メッセージング基盤導入前

あるサーバ間でデータを受け渡したいと思うときどのような仕組みを考えるでしょうか。 一番単純な例だとこのようになります。

非常にシンプルですね。まずはここからスタートしましょう。「データを受け渡す」という点は上記で満たせそうですね。

でも次の場合を考えてみるとどうでしょう。

1. 送り先を追加したい場合

Aはすべての送信先を知っている(設定する)必要があります。また送信先の追加のたびに変更作業をする必要があるでしょう。 また送信元が追加した場合は、その送信元ごとに宛先の追加作業を行う必要があります。

2. 送信先が(オフラインであり)受け取れない状態

送信先がオンラインとなるまでAは待ち続けなくてはいけません。定期的にオンラインかどうかを確認する仕組みも必要でしょう。

3. 送信先が(処理量を超えており)受け取れない状態

AがBの処理量を超えるスピードでメッセージを送っているためにBの負荷が大きくなっている状態です。この状態ではBがいずれメッセージを受け付けなくなってしまいます。最悪の場合メッセージをロストしてしまうこともあるでしょう。

メッセージング基盤導入後

そこで登場したのが「メッセージングキュー(=メッセージング基盤)」という仕組みです。 送信したいノードの間にメッセージを保持して管理するキューを挟むことによって上記の問題を解決します。

さてもう一度、先ほどやりたかったことがどのように解消されるか見ていきましょう。

1. 送り先を追加したい場合

送信元Aはキューに対する宛先だけわかればよくなります。もし、送信元が増えた場合でもすべからずキューに対してメッセージを送ればよくなりますので、宛先の設定は一か所になります。宛先の制御はキューにて行いますので、変更が一か所で済むようになります。 送信先の制御にはメタ情報を付与して送ることになります。 例えば、以下のように本文とは別に送り先を指定してあげるイメージです。

送り先→B宛て

本文→テストメッセージ

キューはその情報に基づき、送り先を変えます。 こちらはキューイングシステムによって「Subject」であったり、「キュー名」だったりと呼称は異なりますが、どちらもメッセージの種類を区別しそれによって宛先を変更します。

2. 送信先が(オフラインであり)受け取れない状態

Aはキューに対してメッセージを投げます。Aはキューにメッセージを投げたタイミングで処理を完了し、次のメッセージの処理が可能になります。 キューはBがオンラインになったタイミングでメッセージを配送します。 AはBの状態を気にすることなく、次の処理を行うことができます。

3. 送信先が(処理量を超えており)受け取れない状態

キューが送信の流量制御を行います。つまりAから受け取ったメッセージをそのまま流すのではなく、Bが処理できる流量に落として配信を行います。

メッセージングキューが備えるべき条件

さて、ここまで「メッセージングキュー」のメリットについてみてきましたが、キューが備えるべき条件も明らかになってきたはずです。

まずは送信先の代わりにデータを受け取るので、キューシステムは常に使用可能な状態にしておく必要があります。もし使えない場合は送信元はデータを送れず、当初の1の課題と同じことになってしまいます。

またメッセージを”確実”に届けるためにデータをロストしてはいけません。

つまり以下が大事な要件ということになります。

・可用性

・堅牢性

では可用性を高めるためにはどのようにしたらよいでしょうか

システムといっても機械なので人為的なミス、ハードウェアの故障、ソフトウェアのバグによってシステムがダウンしてしまうことは発生してしまいます。
まず思いつくのはサブ機を用意することです。 障害が起きたタイミングでサブ機に切り替えを行えば、処理が継続できますね!

では堅牢性を高めるにはどのようにしたらよいでしょうか
データを単一で持つのではなく、2重、3重と複製することで、あるデータが障害により失われてしまった場合でも復旧が可能です。

つまり以下のような構成が望ましいでしょうか。

メッセージング基盤の問題点

上記のモデルは非常によくワークします。
しかしながら、サブ機の切り替えのタイミングで数秒程度使えない状態が存在します。 メイン機が障害が起きたことに気づき、処理開始するまでに多少の時間がかかるからです。

これまではそれでもデータ量が少ない、システムが使えないことによるビジネスインパクトが今ほどは大きくないため許容されてきました。
しかし、昨今はデータドリブンな社会へと変革しており、データが処理できないことがおおきな機会損失、ビジネス上へのネガティブインパクトを与えます。

また、データ量が増えてきて処理量も膨大なものになってきた場合どのように対処するでしょうか。

リソースのスペックをあげることで対応することにしました。
ただし、単一サーバのリソースには限界があり、どこまでもスペックアップできるわけではありません。   

また障害時に同様の流量をさばくために、普段は使っていないのにもかかわらず待機系もスペックアップする必要があり、コストが増加します。

上記の課題を解決するために生まれたのが分散メッセージング基盤となります。 分散と聞くと、大型の企業が非常にたくさんのサーバを用意して処理を行っていることをイメージされるかもしれませんが、いまや各種クラウドベンダーの力により、個人であっても比較的容易にクラウドネイティブな処理が可能になっています。 次の章で分散メッセージング基盤の特徴と解決した課題を見ていきましょう。 (次に続く)