先日以下のような問い合わせをもらった。
問い合わせ
現在ペアのリージョンを使ってHA構成にしているシステムを構築中である。データベースもペアのリージョンに存在し、そのデータベース間でフェールオーバーグループを構成している。テストでデータベースをフェールオーバーさせると、アプリケーションがフェールオーバー先のデータベースにアクセスできなくなった。VNetはグローバルピアリングしており、ネットワーク的につながらないことはないはず。何が問題だったのか。どうすれば解決できるか。
もう少し詳しく聞いてみた。
- 一方のリージョンがActive、他方のリージョンがStand-byのHA構成のシステム。前段にはTraffic Managerがあり、優先度による振り分けを構成済み。Activeリージョンで障害が発生した場合は、リージョンの切り替え、すなわちTraffic Managerで負荷分散先を変えることで対応する。
- 両リージョンに存在する仮想ネットワークはペアのリージョン間でグローバルピアリングが構成されている。
- データベースはSQL Databaseを使っており、自動フェールオーバーグループを利用している。そのため、リスナーは地理透過性があり、接続文字列をフェールオーバーのタイミングで書き換える必要はない。
- アプリケーションはApp Serviceで稼働している。仮想ネットワークに統合されており、データベースアクセスが必要なアプリケーションはSQL Databaseへのサービスエンドポイントが構成されたサブネットに属している。また、APIを提供するApp Serviceもあるため、App Serviceへのサービスエンドポイントも構成されている。
- データベースのフェールオーバーにより、データベースのプライマリーが稼働するリージョンと、Traffic Managerがトラフィックを流す先のリージョン、つまりアプリケーションの稼働リージョンが一致しなくなる場合がある。つまり、ペアリージョン間でクロスする形でデータベースにアクセスする場合がある、とのこと。
つまり、以下のような構成らしい。

どこに問題があるのか
以下のドキュメントにも記載がある通り、サービスエンドポイントはリージョンをまたいで構成できない。
Azure SQL の場合、サービス エンドポイントは、仮想ネットワークのリージョン内の Azure サービス トラフィックにのみ適用されます。
制限事項 / Limitations
https://docs.microsoft.com/azure/virtual-network/virtual-network-service-endpoints-overview#limitations
つまり、アクセス先のデータベース(プライマリー)が同じリージョンなら大丈夫。

しかし、以下のいずれかの条件下で、アプリケーションとデータベースの接続がリージョンをクロスする形になった場合、接続に失敗する。ここでグローバルピアリングの有無は関係ない。
- フェールオーバーグループ内でデータベースがフェールオーバーした場合
- データベースはフェールオーバーしていないが、アプリケーションに何らかの障害が発生して、プローブの応答からTraffic Managerがその時点のActiveリージョンで障害が発生したと認識し、別のリージョンにトラフィックが振られた場合

解決策
解決方法は大きく分けて2種類。
- プライベートエンドポイントの利用(Global peeringとの組み合わせも可)
- Traffic ManagerやFront Doorによるルーティングルールの変更
1. プライベートエンドポイントの利用
データベースとの接続をサービスエンドポイントからプライベートリンク / エンドポイントに変える、ということ。SQL Databaseとのプライベートリンク / エンドポイントは以下を参照。
Azure SQL Database と Azure Synapse Analytics に対する Azure Private Link / Azure Private Link for Azure SQL Database and Azure Synapse Analytics
https://docs.microsoft.com/azure/azure-sql/database/private-endpoint-overview
プライベートエンドポイント / プライベートリンクの注意点は以下のエントリにも記載している。
Azure Private Link
https://logico-jp.io/2020/02/25/azure-private-link/
VNet統合したApp Serviceから、プライベートエンドポイント / プライベートリンクで接続したSQL Databaseにアクセスする上でのTipsは以下のドキュメントに記載がある。
Azure SQL データベースへの Web アプリのプライベート接続 / Web app private connectivity to Azure SQL database
https://docs.microsoft.com/azure/architecture/example-scenario/private-web-app/private-web-app
構成はこんな感じ。

この構成の場合、両リージョンのSQL DatabaseにアクセスするPrivate Endpointは両リージョンのVNetに配置されていて、しかもVNet peeringされていないので、SQL DatabaseのPrivate Endpoint/Linkの名前解決で利用するPrivate DNS ZoneはRegion-AのリソースグループとRegion-Bのリソースグループに配置する必要がある。
これに加え、両リージョンのVNetをglobal peeringしている場合には、SQL DatabaseのPrivate Endpoint/Linkの名前解決で利用するPrivate DNS Zoneを1個だけ作成し、両リージョンのVNetを当該ZoneにVNetリンクすることもできる。
何れにしても、WebアプリはRegion-Aで稼働するが、DBはRegion-Bで稼働する、というしくみを構成できる。後者(Global peering時)の構成のポイントは以下のドキュメントに記載がある。
Multi-region web app with private connectivity to database
https://docs.microsoft.com/azure/architecture/example-scenario/sql-failover/app-service-private-sql-multi-region
これにより、クロスした形でのデータベースアクセスも可能になるが、以下の点は考慮が必要。
- おかね
- サービスエンドポイントとは異なり、少々費用がかかる
- データベースとの接続はリージョンまたぎの接続なので、ネットワークトラフィックに対する従量課金が発生する
- パフォーマンス
- SQL Databaseへの接続はリダイレクトではなく、プロキシ接続になるため、スループットが落ちる
- データベースとの接続がリージョンまたぎの接続になると、ネットワークレイテンシが大きくなる
価格などの情報は以下。
Azure Private Linkの価格 / Azure Private Link pricing
https://azure.microsoft.com/pricing/details/private-link/
接続ポリシー / Connection policy
https://docs.microsoft.com/azure/azure-sql/database/connectivity-architecture#connection-policy
3. Traffic ManagerもしくはFront Doorによるルーティングルールの変更
データベース接続のネットワークレイテンシやスループットが重要なアプリケーションの場合、プライベートエンドポイントを選択するのが困難な場合がある。この場合、Traffic Managerのエンドポイント監視の機能を利用し、データベース接続が切れた(フェールオーバーが発生した)タイミングで、プローブとなるAPIからの応答を変更することで、Traffic Managerにトラフィックルーティング先を変更させる、というもの。つまりは、データベースのプライマリーリージョンとアプリケーションが稼働するリージョンを一致させる、ということ。こんな感じ。

具体的には以下の作業や設定が必要。
優先度設定
まず、Traffic Managerのバックエンドへのルーティング優先度を大きな差にしておく。今回はペア・リージョン間でHA構成にしているので、Region-Aを50、Region-Bを1000などにしておく。これにより、通常はRegion-Aにトラフィックがルーティングされる。詳細は以下(なお、この問い合わせ元ではすでに優先度設定が構成済みなので、この設定は特に実施していない)。
優先順位トラフィック ルーティング方法 / Priority traffic-routing method
https://docs.microsoft.com/azure/traffic-manager/traffic-manager-routing-methods#priority-traffic-routing-method
ヘルスチェックAPI
つづいて、通常のユーザーアクセスを模してシステムをテストできるようなAPIを作成する。正常であれば200、異常(データベース接続が切れた、など)では503などを返すようにしておく。このAPIをエンドポイント監視の設定に登録して、エンドポイントを監視する。詳細は以下。
エンドポイント監視のしくみ / How endpoint monitoring works
https://docs.microsoft.com/azure/traffic-manager/traffic-manager-monitoring#how-endpoint-monitoring-works
以下のドキュメントの記述の通り、エンドポイントからの応答に対する対応を構成できる。
エンドポイントのフェールオーバーと復旧 / Endpoint failover and recovery
https://docs.microsoft.com/azure/traffic-manager/traffic-manager-monitoring#endpoint-failover-and-recovery
この方式の場合、以下を考慮しておく必要がある。
- リージョン切り替えまでに、ヘルスチェックAPIによるエンドポイント監視の最小間隔と試行回数だけは時間が必要。Traffic Managerの場合以下の通り。
- プローブによる最小監視間隔はデフォルトは30秒。10秒間隔にもできるが、追加費用が必要。
- エラー許容回数は0から9まで。0の場合、プローブから1回でもエラーを返すと、Traffic Managerは当該リージョンが異常であると判断する。
- ヘルスチェックAPIを作成していないのであれば、作成が必要(もちろん、既存の呼び出しを工夫して代用できるならそれでもかまわない。全く持ち合わせていないのであれば、作っておいて損はない)。
まとめ
今回の場合、データベースのフェールオーバーに素直に対応する(ただしコストの負担は必要)、それともデータベースのフェールオーバーによりアプリケーションが正常ではないことを認識してリージョンを切り替える(ただし異常検出までに時間が必要)、の両方の方法を紹介し、状況やシステム特性に合わせて選択してもらうようにした。なお、この問い合わせではTraffic Managerを前段に配置していたが、Azure Front Doorであっても同様の考え方で対応できる。