mozblog - もずぶろぐ -

自分のための備忘録や日記など。

Azure Event Hubs をいい感じにわかりやすくしたい

 最近、仕事で Azure Event Hubs を使う機会が多くあります。
しかしながら、どうも Microsoft さんの公式ドキュメントが分かりづらい・・・(失礼
そこで、Event Hubs をどうにか、ざっくりいい感じに、まとめれないかと試みました。
私の個人的な理解なので、正しくない部分も多々あるかもしれませんが、もし気づいた方はご指摘いただけると幸いです。

 

1. Event Hubs とは?

AMQP や HTTP といったプロトコルを使って、大量のメッセージを中継することができるハブです。(公式ドキュメントでは、メッセージを「イベント」と記載しているようです。)
OSS 製品だと RabbitMQ などが近いでしょうか。
例えば、数千台の機器からセンシングしたデータを Event Hubs に送信し、受信用のクライアントが Event Hubs からデータを読み出し加工を行い、データベースに保存することができます。

 Azure 上の類似サービスでは、IoT Hub や Service Bus などがあります。

IoT Hub は Event Hubs 互換エンドポイントと呼ばれるものをもっているくらいなので、かなり類似のサービスではありますが、IoT Hub は受信側もクライアントも多くのデバイスを接続できます。

Service Bus は、中継するメッセージに対して、多くのコントロールができるサービスです。
例えば、Service Bus には、配信に失敗したメッセージを格納する Dead Letter Queue という機能や、受信したメッセージをキューから削除するような機能があります。

 

2. Event Hubs の注意点

・Event Hubs は、送信クライアントはたくさん接続してメッセージを送ることができますが、受信クライアントはあまり多くを繋ぐことができません。
あくまで受信側はメッセージの処理サーバーを繋ぐような用途が想定されています。

・送信および受信クライアントともに、IP アドレスで接続を制限することができません。
パブリックなエンドポイントが外部に公開されます。

・Event Hubs に着信したメッセージを削除する操作ができません。
着信したメッセージは、メッセージの保存期間が過ぎるまで、消すことができません。
また、検証してみたところ、保存期間が過ぎたらメッセージが必ず消されるわけではなく、保存期間はあくまで「いつまで確実に残しておくか」を表す設定のようです。

・どこまでメッセージを読み出したか、記録する機能は、Event Hubs 側にはありません。
ただ、どの地点からメッセージを読み出すか、指定することはできるので、受信クライアント側で、どこまでメッセージを読み出したか管理する必要があります。
どの地点からメッセージを読み出すか指定しない場合、Event Hubs では処理済みのメッセージを削除する機能がないので、最初からメッセージを読みなおすことになります。

 

3. Event Hubs の構成

名前空間

Azure で Event Hubs を作成する際は、まず一番最初に名前空間と呼ばれるものを定義します。
名前空間は Event Hubs の FQDN に利用されます。
たとえば、名前空間hoge とすると、hoge.servicebus.windows.net という FQDN が払い出されます。
FQDN として利用されるので、名前空間はグローバルでユニークである必要があります。

 Event Hub

名前空間を作成したあとに、Event Hub の実体が作成できます。
これは、ひとつの名前空間の中に複数の Hub が作成できるようになっており、現在はひとつの名前空間に対し最大で 10 個まで作れるようです。
例えば、hoge.servicebus.windows.net/hub1 と hoge.servicebus.windows.net/hub2 という形で、複数作成できます。
また、FQDN に使われるものではないため、グローバルでユニークである必要はなく、名前空間のなかでユニークであれば OK です。

スループット ユニット

Event Hub を構成するインスタンスで、増やすほど送受信のスループットが向上しますが、その分料金も高くなります。
最近は auto-inflate という機能が追加され、通信負荷に応じて自動でスケールできるようになったようです。

パーティション

個人的に、Event Hub で一番難しい概念が、このパーティションだと思います。

Event Hub に到達したメッセージは、パーティションに分割して、保存されます。
たとえば、パーティションの数を 4 つと設定した状態で、メッセージを 8 件送信すると、パーティションあたり 2 件ずつメッセージが保存されることになります。

Event Hubs では、メッセージの順序性はパーティション内で保証され、パーティションをまたいでは保証されません。つまり、メッセージの送信順を 0 - 7 とすると、

(Partition 0) 0, 3
(Partition 1) 1, 2
(Partition 2) 4, 6
(Partition 3) 5, 7

といった形で格納される場合があり得る、ということになります。

また、メッセージの送信時にはパーティションを直接指定して送ることもできますが、負荷が偏るため、これは推奨されないようです。
順序を保って送る必要がある場合のみ、パーティションを指定して送るようにしましょう。

パーティションの数は、受信クライアントの台数にかかわります。
さきほどの例だと、パーティションが 4 つなので、受信クライアントは最大で 4 つ接続するような方式が考えられます。
つまり、メッセージは 4 並列に処理できることになります。
もちろん、ひとつのパーティションに複数の受信クライアントを接続することもできますが、Event Hubs ではメッセージを読み出してもメッセージは削除されないため、メッセージ処理が重複して行われることになります。

パーティションの数は、増やしたとしても料金は変わらないようで、最大で 32 個まで作成できます。
しかし、後から変更できないので、あらかじめどこまで並列にするか予測する必要があるかと思います。

コンシューマー グループ

これもパーティションの次に難しい概念だと思います。

受信クライアントは、Event Hub のパーティションに直接接続するのではなく、コンシューマー グループという概念を経由して接続するような形になります。

ひとつのコンシューマー グループを経由して、あるパーティションに接続する受信クライアントは、1 つのみであることが推奨されています。

これだけでは分かりづらいので、以下の設定値の場合、接続がどうなるか考えてみます。

パーティション数:4
受信クライアント数:2
コンシューマー グループ数:1

接続はこんな感じになります。

(Partition 0) <- (Consumer Group 0) <- (Receiver 0)
(Partition 1) <- (Consumer Group 0) <- (Receiver 0)
(Partition 2) <- (Consumer Group 0) <- (Receiver 1)
(Partition 3) <- (Consumer Group 0) <- (Receiver 1)

一応、仕様としては、ひとつのコンシューマー グループを経由して、パーティションに 5 つまでの受信クライアントを接続できるようですが、1 つにすることが推奨されています。
もしひとつのパーティションに複数の受信クライアントを接続したいときは、コンシューマーグループを複数用意したほうが、管理上見やすいという意味合いがあるからかと思います。

 

 

というわけで、Event Hubs サービスの主要概念を見てきました。
いつか、EventProcessorHost など、Microsoft にて作られている、受信クライアントのライブラリなども紹介できればと思います。