メッセージ レプリケーションとリージョン間フェデレーション

名前空間内では、Azure Service Bus により、さまざまなルーティング パターンの実装に対応するための、自動転送を使用したチェーン キューとトピック サブスクリプションのトポロジの作成がサポートされています。 たとえば、パートナーが送信または受信アクセス許可を持ち、必要に応じて一時的に中断できる専用のキューをパートナーに提供し、アプリケーションに対してプライベートな他のエンティティに柔軟に接続することができます。 また、複雑なマルチステージ ルーティング トポロジを作成したり、メールボックス スタイルのキューを作成することもできます。これにより、キューのようなトピックのサブスクリプションがドレインされ、サブスクライバーごとにより多くのストレージ容量を使用できるようになります。

多くの高度なソリューションでは、これらや他のパターンを実装するために、名前空間の境界を越えてメッセージをレプリケートする必要もあります。 複数の異なるアプリケーション テナントに関連付けられた名前空間の間、または複数の異なる Azure リージョンの間を、メッセージがフローすることが必要な場合があります。

ソリューションにより、異なるリージョンに複数の Service Bus 名前空間が保持されて、キューとトピックの間でメッセージがレプリケートされたり、Azure Event HubsAzure IoT HubApache Kafka などのソースとターゲットでメッセージが交換されたりします。

この記事では、これらのシナリオに焦点を当てます。

フェデレーション パターン

キューやトピックなどの Service Bus エンティティの間、または Service Bus と他のソースやターゲットの間でメッセージを移動する場合は、さまざまな動機が考えられます。

Event Hubs の同様のパターン セットと比較して、キューに似たエンティティのフェデレーションはより複雑になります。これは、メッセージ キューにより、コンシューマーに対して 1 つのメッセージの排他的所有が約束され、メッセージ配信の到着順序が維持され、ブローカーで競合するコンシューマー間のメッセージの均等な配分が調整されるためです。

CAP 定理の制約など、実際的な障害があります。これにより、複数のリージョンで同時に使用可能なキューの統合ビューを提供することが難しくなり、リージョン間に分散する競合コンシューマーでメッセージの所有権を排他的に取得することができます。 このような geo 分散キューでは、メッセージがコンシューマーで使用できるようになる前に、メッセージだけでなく、すべてのメッセージの配信状態についても、完全に整合性のあるレプリケーションが必要です。 仮想的なリージョン間に分散したキューに対する完全な一貫性の目標は、Azure Service Bus のほとんどのユーザーがフェデレーションのシナリオを検討するときに抱く次のような主要な目標と直接競合します: ソリューションの最大限の可用性と信頼性。

したがって、ここで示すパターンの焦点は可用性と信頼性ですが、情報の損失とメッセージの重複処理の両方を回避することも目的としています。

リージョンの可用性イベントからの回復性

最大の可用性と信頼性は Service Bus の運用上の最優先事項ですが、ネットワークや名前解決の問題のため、または Service Bus エンティティが一時的に応答不能になったりエラーを返したりするため、プロデューサーやコンシューマーが割り当てられた "プライマリ" Service Bus と通信できなくなる、多くの可能性があります。 指定されたメッセージ プロセッサが使用できなくなる可能性もあります。

このような状況は、ディザスター リカバリーで行われる場合があるリージョンのデプロイの完全な破棄が必要な "壊滅的" なものではありませんが、一部のアプリケーションのビジネス シナリオは、数分または数秒より長くは続かない可用性イベントの影響を受けている可能性があります。 Azure Service Bus は、多くの場合、ハイブリッド クラウド環境や、ネットワーク エッジに存在するクライアント (小売店、レストラン、銀行支店、製造サイト、物流施設、空港など) で使用されます。 ネットワーク ルーティングや輻輳の問題の影響で、あるサイトが割り当てられた Service Bus エンドポイントには到達できないのに、別のリージョンのセカンダリ エンドポイントには到達できるような状況が発生する可能性があります。 同時に、これらのサイトから到着したメッセージを処理するシステムは、プライマリとセカンダリ両方の Service Bus エンドポイントに問題なくアクセスできる可能性があります。

ネットワーク ルーティングの問題や、Service Bus エンティティの一時的な可用性の問題の影響に対するビジネスの耐性が低い、このようなハイブリッド クラウド アプリケーションやエッジ アプリケーションの実際的な例が多くあります。 そのようなものとしては、小売サイトでの支払い処理、空港ゲートでの搭乗、レストランでの携帯電話の注文などがありますが、そのすべては、信頼性の高い通信パスが使用できない場合は常に、すぐに完全に停止します。

このカテゴリでは、"すべてアクティブ" レプリケーション、"アクティブ - パッシブ" レプリケーション、"スピルオーバー" レプリケーションという 3 つの異なる分散パターンについて説明します。

すべてアクティブ レプリケーション

"すべてアクティブ" レプリケーション パターンを使用すると、同じ論理トピック (またはキュー) のアクティブなレプリカを複数の名前空間 (およびリージョン) で使用できるようになり、すべてのメッセージがエンキューされた場所に関係なくすべてのレプリカで使用できるようになります。 このパターンの場合、一般に、メッセージの順序はすべてのパブリッシャーに対して保持されます。

すべてアクティブ パターン

図に示されているように、このパターンは一般に Service Bus トピックに依存します。 レプリケーション スキームに参加する必要がある、名前空間ごとに 1 つのトピック。 これらの各トピックには、メッセージをレプリケートする必要のある他のすべてのトピックに対して 1 つの "レプリケーション サブスクリプション" があります。 上の図では、トピックのペアは 1 つだけなので、他のトピックに対する 1 つのレプリケーション サブスクリプションがあります。 3 つの名前空間 {n1, n2, n3} があるシナリオでは、名前空間 n1 のトピックには、2 つのレプリケーション サブスクリプションがあります。1 つは n2 の対応するトピック用で、もう 1 つは n3 の対応するトピック用です。

各レプリケーション サブスクリプションには、SQL フィルター式 (replicated <> 1) と SQL アクション (set replicated = 1) を組み合わせたルールがあります。 ルールのフィルターにより、カスタム プロパティ replication が設定されていない、または値 1 でないメッセージのみが、このサブスクリプションの対象になり、アクションにより、その後で選択されたメッセージごとにそのプロパティが値 1 に設定されます。 その結果、メッセージが対応するトピックにコピーされるときには、逆方向のレプリケーションの対象にならなくなるため、レプリカ間でメッセージがバウンスされることはありません。

次のような Azure CLI を使用して、個別のルールを持つサブスクリプションを任意のトピックに簡単に追加できます。


az servicebus topic subscription rule create --resource-group myresourcegroup \
   --namespace mynamespace --topic-name mytopic \
   --subscription-name replication --name replication \
   --action-sql-expression "set replication = 1" \
   --filter-sql-expression "replication IS NULL"

キューをモデル化するため、各トピックは、すべてのコンシューマーが共有する 1 つの標準サブスクリプション (レプリケーション サブスクリプション以外) に制限されます。

すべてアクティブ レプリケーション モデルの場合、いずれかのトピックに送信されたすべてのメッセージのコピーが各トピックに挿入されます。 これは、各リージョンのアプリケーション コードですべてのメッセージが認識されて処理されることを意味します。 このパターンは、データが複数のリージョンで共有される場合、または冗長な処理が一般に必要な場合に適しています。 通常のキューのように、すべてのメッセージが 1 回だけ処理される必要がある場合は、次の 2 つのパターンのいずれかを考慮する必要があります。

アクティブ - パッシブ レプリケーション

"アクティブ - パッシブ" レプリケーション パターンは、前のパターンのバリエーションであり、1 つのトピック ("プライマリ") のみがメッセージの送受信用にアプリケーションによって使用され、プライマリ トピックが使用不能または到達不能になる場合に備えて、メッセージはセカンダリ トピックにレプリケートされます。

アクティブ - パッシブ パターン

このパターンと前のパターンの主な違いは、レプリケーションがプライマリ トピックからセカンダリ トピックへの一方向である点です。 セカンダリ トピックは、プライマリになることはなく、プライマリ トピックが一時的に使用できない場合のバックアップ オプションです。

このパターンを使用する利点は、処理の重複が最小限に抑えられることです。 レプリケーションの間に、プライマリで障害が発生した場合にフェールオーバーが行われるまでの予想時間を反映した TimeToLive メッセージ プロパティが、レプリケートされるメッセージに設定されます。 たとえば、ユース ケース シナリオで、プライマリからのメッセージの取得で問題が発生し始めてから 1 分以内にコンシューマーをセカンダリに切り替える必要がある場合、セカンダリでは、プライマリでアクセスできないすべてのメッセージを使用でき、問題発生前にプライマリから既に処理されたメッセージの数が最小限になるのが理想です。 レプリケーションの間に TimeToLive をその期間の 2 倍 (2 分) に設定すると (ルール アクションで set sys.TimeToLive = '0:2:0')、セカンダリには 2 分間のメッセージのみが保持され、それより古いものは破棄されます。 つまり、セカンダリに切り替えられた受信側では、メッセージが速やかに読み取られ、最後に処理されたものより古いものは破棄されて、まだ認識されていない最初のメッセージから処理することができます。 実際の保持期間は、特定のユース ケースと、どれくらい速くアプリケーションでセカンダリに切り替える必要があり、それが可能かによって異なります。 TimeToLive の設定は、数秒から数日の範囲内で受け入れられます。

アプリケーションでセカンダリが使用されている間は、セカンダリ トピックに直接発行することもできます。それは、通常のトピックとして機能します。 セカンダリに切り替わった後、コンシューマーには、レプリケートされたメッセージと、セカンダリに直接パブリッシュされたメッセージの両方が認識されます。 そのため、アプリケーションでは、最初に発行をプライマリに切り替えて、コンシューマーをセカンダリに戻す前に、ローカルで発行されたメッセージをドレインできる必要があります。 プライマリが再び使用可能になると、レプリケーションは自動的に再開されるので、コンシューマーは、多少待機時間は長くなりますが、その間にプライマリに対して発行された新しいメッセージも取得します。

このパターンは、メッセージが 1 回だけ処理される必要があるシナリオに適しています。 アプリケーションでは、セカンダリでのフェールオーバー期間中に重複が検出され、元に切り替えるときに再び重複が検出されるため、プライマリから処理されたメッセージを追跡する必要があります。 重複除去の条件には、アプリケーション提供の MessageId を使用するのが最適です。 EnqueuedTimeUtc の値もウォーターマーク インジケーターとして適していますが、アプリケーションでは、分散システムと同様に、プライマリとセカンダリの間で一定の時間差 (数秒) を許容する必要があります。

スピルオーバー レプリケーション

"スピルオーバー" レプリケーション パターンを使用すると、複数のリージョンにある複数の Service Bus エンティティをアクティブ - アクティブで使用して、Service Bus は正常であっても、"コンシューマー" が多数の保留中メッセージを処理できなくなったり、完全に使用できなくなったりするシナリオに対処できます。 その理由としては、コンシューマー プロセスのバックにあるデータベースが遅くなったり、使用できなくなっている可能性があります。 このパターンは、単純なキューとトピック サブスクリプションで動作します。

スピルオーバー レプリケーション

図で示されているように、スピルオーバー レプリケーション パターンの場合は、キューまたはサブスクリプションに関連付けられている配信不能キューから、異なる名前空間内のペアになっているキューまたはトピックに、メッセージがレプリケートされます。

障害が発生していなくても、2 つの名前空間は並列に使用され、それぞれがメッセージ トラフィック全体の一部のサブセットを受信し、それに関連付けられているコンシューマーによってサブセットが処理されます。 いずれかのコンシューマーが高いエラー率を示し始めたり、完全に停止したりすると、配信数を超えるか、期限切れのため、それぞれのメッセージは配信不能キューに格納されます。 その後、それらはレプリケーション タスクによって取得されてペアになっているキューに再エンキューされ、正常と思われるコンシューマーに提供されます。

特定の期限内に処理が行われる必要がある場合は、スピルオーバー セカンダリによって時間内に処理できるように、キューやメッセージの TimeToLive を設定する必要があります。たとえば、TimeToLive を許容時間の半分に設定します。

すべてアクティブ パターンと同様に、アプリケーションでは、メッセージがキューのペア間でバウンスされるのではなく、複合パターンの配信不能キューとして機能する補助キューに格納されるように、既にレプリケートされたかどうかを示すインジケーターをメッセージに追加できます。

このパターンは、コンシューマーまたはコンシューマーが依存しているリソースの可用性の問題を防ぐこと、およびペアになっているキューの 1 つにトラフィックの急増を再分配することが最も重要であるシナリオに適しています。 また、コンシューマーが両方のキューから読み取る場合に、いずれかの名前空間が使用不能になるのを防ぐこともできますが、TimeToLive の有効期限によって発生するレプリケーションの遅延により、その時間枠内のメッセージが使用できない名前空間で孤立する可能性があります。

待機時間の最適化

トピックは、複数のコンシューマーに情報を配布するために使用されます。 場合によっては、特に地理的に広く分散しているコンシューマーの場合は、トピックからのメッセージを、コンシューマーに近いセカンダリ名前空間内のトピックにレプリケートするのがよい場合があります。

待機時間の最適化

たとえば、大陸のリージョン ハブ間でデータを共有する場合、ハブ間で 1 回だけ情報を転送し、コンシューマーでそれらのハブからデータのコピーを取得する方が効率的です。

レプリケーション転送はバッチで行うことができ、コンシューマーは多くの場合、1 つずつメッセージを取得して終了します。 たとえば北米とヨーロッパの間のベース ネットワーク待機時間が 100 ms である場合、メッセージを取得して終了するために、リモート エンティティに 2 回ラウンドトリップすると、同じリージョン内のエンティティと比較して、メッセージごとに 200 ms 余計にかかることになります。

検証、削減、強化

独自のソリューションの外部にあるクライアントによって、メッセージが Service Bus キューまたはトピックに送信される場合があります。

検証、削減、エンリッチメント

このようなメッセージの場合、特定のスキーマに準拠しているかどうかを確認し、準拠していないメッセージは削除または配信不能にすることが、必要になる場合があります。 メッセージによっては、データを省略することによって複雑さを軽減したり、参照データの検索に基づいてデータを追加することにより強化したりすることが、必要な場合もあります。 操作は、レプリケーション タスクのカスタム機能を使用して実行できます。

キュー レプリケーションへのストリーム

Azure Event Hubs は、大量の受信イベントを処理するのに理想的なソリューションです。 ただし、Event Hubs でも、Apache Kafka のような同様のエンジンでも、サービスによって管理される競合コンシューマー モデルは提供されていません。このモデルでは、重複して処理されるリスクなしに、複数のコンシューマーが同じソースからのメッセージを同時に処理し、処理が完了したら最終的にメッセージを終了することができます。

統合

キュー レプリケーションへのストリームにより、単一のイベント ハブ パーティションまたは完全なイベント ハブの内容が Service Bus キューに転送され、そこからメッセージを競合コンシューマーで安全にトランザクション処理することができます。 また、このレプリケーションにより、トピックでのルーティングや、セッション ベースの多重化解除など、他のすべての Service Bus 機能もそれらのメッセージに対して使用できます。

統合と正規化

グローバル ソリューションは、多くの場合、独自の処理機能など、主に独立しているリージョンのフットプリントで構成されますが、リージョンを超えたグローバルな観点では、データの統合、つまりローカルの観点では各リージョンのフットプリントで評価される同じメッセージ データの一元的な統合が必要になります。

統合

正規化は統合シナリオのフレーバーであり、複数の受信メッセージ シーケンスに同じ種類の情報が含まれますが、構造やエンコードが異なるため、使用する前に、メッセージをトランスコードまたは変換する必要があります。

また、正規化には、エンド ツー エンドで暗号化されたペイロードの解読や、ダウンストリームのコンシューマー対象ユーザー向けの異なるキーとアルゴリズムでの再暗号化など、暗号化処理が含まれる場合があります。

分割とルーティング

Service Bus のトピックとそのサブスクリプション ルールは、多くの場合、特定の対象ユーザー向けにメッセージのストリームをフィルター処理するために使用され、その対象ユーザーはサブスクリプションからフィルター処理されたセットを取得します。

分割

それらのメッセージの対象ユーザーがグローバルに分散している、または異なるアプリケーションに属しているグローバル システムでは、レプリケーションを使用して、そのようなサブスクリプションから異なる名前空間のキューまたはトピックにメッセージを転送して、そこから使用することができます。

Azure Functions でのレプリケーション アプリケーション

上記のパターンを実装するには、構成して実行するレプリケーション タスクのための、スケーラブルで信頼性の高い実行環境が必要です。 Azure でステートレス タスクに最適なランタイム環境は Azure Functions ます。

Azure Functions は Azure マネージド ID で実行でき、レプリケーション パスに沿ってシークレットを管理する必要なしに、レプリケーション タスクをソースやターゲットのサービスのロールベースのアクセス制御ルールと統合できます。 レプリケーションのソースとターゲットで明示的な資格情報が必要な場合は、Azure Functions で Azure Key Vault 内の厳格にアクセス制御されたストレージに、それらの資格情報の構成値を保持できます。

さらに、Azure Functions を使用すると、レプリケーション タスクをすべての Azure メッセージング サービス用の Azure 仮想ネットワークやサービス エンドポイントと直接統合することができ、Azure Monitor と簡単に統合できます。

最も重要なのは、Azure Functions には、Azure Event HubsAzure IoT HubAzure Service BusAzure Event GridAzure Queue StorageRabbitMQ 用のカスタム拡張機能、Apache Kafka のための、あらかじめ構築されたスケーラブルなトリガーと出力バインドがあることです。 多くのトリガーは、ドキュメント化されたメトリックに基づいて、同時実行インスタンスの数を増減することにより、スループットのニーズに動的に適応します。

Azure Functions の従量課金プランを使用すると、レプリケーションに使用できるメッセージがない場合は、事前に構築されたトリガーをゼロにスケールダウンすることさえできます。これにより、再度スケールアップできるよう構成を維持するためのコストが発生しなくなります。 従量課金プランを使用する場合の主な欠点は、この状態からレプリケーション タスクを "ウェイクアップする" ための待機時間が、インフラストラクチャが実行されたままになるホスティング プランより大幅に長くなることです。

このすべてと対照的に、メッセージングとイベントのための最も一般的なレプリケーション エンジン (Apache Kafka の MirrorMaker など) では、ユーザーがホスティング環境を提供し、レプリケーション エンジンを自分でスケーリングする必要があります。 それには、セキュリティとネットワークの機能を構成して統合したり、監視データのフローを可能にしたりすることが含まれます。それなのに、カスタム レプリケーション タスクをフローに挿入することはできません。

Azure Logic Apps を使用したレプリケーション タスク

Functions を使用してコーディング以外の方法でレプリケーションを行うには、Logic Apps を代わりに使用します。 Logic Apps では、Service Bus 用のレプリケーション タスクが事前に定義されています。 これらは、異なるインスタンス間のレプリケーションの設定に役立ち、追加でカスタマイズするように調整できます。

次の手順

この記事では、さまざまなフェデレーション パターンを調べ、Azure でのイベントとメッセージングのレプリケーション ランタイムとしての Azure Functions の役割について説明しました。

次に、Azure Functions でレプリケーター アプリケーションをセットアップする方法と、Event Hubs と他のさまざまなイベントおよびメッセージング システムの間でイベント フローをレプリケートする方法について読むことをお勧めします。