Share via


Azure SignalR Service の回復性とディザスター リカバリー

回復性とディザスター リカバリーは、各種オンライン システムに共通の要件です。 Azure SignalR Service は既に 99.9% の可用性を提供していますが、それでもリージョン サービスです。 リージョン全体の停止が発生した場合、サービス インスタンスは常に 1 つのリージョンで実行されるため、別のリージョンにフェールオーバーされません。

リージョンのディザスター リカバリーを行う場合は、次の 2 つの方法をお勧めします。

  • geo レプリケーションを有効にする (簡単な方法)。 この機能は、リージョンのフェールオーバーを自動的に処理します。 有効にすると、Azure SignalR インスタンスは 1 つしかなく、コードの変更は導入されません。 詳細については、geo レプリケーションを確認してください。
  • サービス SDK で複数のエンドポイントを使用する。 サービス SDK では、複数の SignalR サービス インスタンスがサポートされ、一部が使用できない場合は自動的に他のインスタンスに切り替えられます。 この機能を利用すれば、障害発生時に復旧できるようになりますが、適切なシステム トポロジをご自分で設定する必要があります。 このドキュメントでは、その方法について説明します。

SignalR サービスの高可用性アーキテクチャ

SignalR サービスのリージョン間の回復性を確保するには、異なるリージョンに複数のサービス インスタンスを設定する必要があります。 そうすることで、1 つのリージョンがダウンしても、その他のリージョンをバックアップとして使用することができます。 アプリ サーバーが複数のサービス インスタンスに接続する際には、プライマリとセカンダリという 2 つのロールが存在します。 プライマリはオンライン トラフィックの受信を担当するインスタンスですが、セカンダリは完全に機能するフォールバック インスタンスとして機能します。 SDK の実装では、ネゴシエートはプライマリ エンドポイントのみを返すので、クライアントは通常の場合にのみプライマリ エンドポイントに接続します。 しかし、プライマリ インスタンスがダウンしているときは、クライアントが引き続き接続できるよう、ネゴシエートでセカンダリ エンドポイントが返されます。 プライマリ インスタンスとアプリ サーバーは、通常のサーバー接続を介して接続されますが、セカンダリ インスタンスとアプリ サーバーは、弱い接続と呼ばれる特殊な接続を介して接続されます。 弱い接続の特徴の 1 つは、別のリージョンのセカンダリ インスタンスの場所が原因でクライアント接続ルーティングを受け入れることができないということです。 クライアントを別のリージョンにルーティングすることは最適な選択ではありません (待ち時間が長くなります)。

1 つのサービス インスタンスを複数のアプリ サーバーに接続するとき、そのインスタンスには、複数のロールを割り当てることができます。 リージョン間シナリオの一般的なセットアップの 1 つは、SignalR サービス インスタンスとアプリ サーバーのペアを 2 つ以上持つことです。 それぞれのペア内でアプリ サーバーと SignalR サービスとが同じリージョン内に存在し、SignalR サービスは、プライマリ ロールとしてアプリ サーバーに接続されます。 ペアとペアの間でも、アプリ サーバーと SignalR サービスとが接続されますが、SignalR は、別のリージョン内のサーバーに接続するときにはセカンダリとなります。

このトポロジであっても、すべてのアプリ サーバーと SignalR サービス インスタンスが相互接続されているので、一方のサーバーからすべてのクライアントにメッセージを配信することはできます。 ただし、クライアントが接続されると、最適なネットワーク待ち時間を実現するために、同じリージョン内のアプリ サーバーにルーティングされます。

次の図は、このようなトポロジを示しています。

Diagram shows two regions each with an app server and a SignalR service, where each server is associated with the SignalR service in its region as primary and with the service in the other region as secondary.

複数の SignalR サービス インスタンスを構成する

複数の SignalR サービス インスタンスは、アプリ サーバーと Azure Functions の両方でサポートされています。

SignalR サービスとアプリ サーバーまたは Azure Functions を各リージョンに作成したら、すべての SignalR サービス インスタンスに接続するようにアプリ サーバーまたは Azure Functions を構成できます。

アプリ サーバーで構成する

それには次の 2 とおりの方法があります。

config による方法

環境変数/アプリの設定/web.cofig から Azure:SignalR:ConnectionString という名前の config エントリで SignalR サービスの接続文字列を設定する方法をご存知のはずです。 複数のエンドポイントがある場合は、複数の config エントリでそれらを設定してください。それぞれ次の形式で設定します。

Azure:SignalR:ConnectionString:<name>:<role>

ConnectionString では、エンドポイントの名前であり、 <name><role> そのロール (プライマリまたはセカンダリ) です。 名前は省略可能ですが、複数のエンドポイント間でルーティングの動作をさらにカスタマイズしたい場合に役立ちます。

コードによる方法

どこか他の場所に接続文字列を保存したい場合は、コードからそれらを読み取って、AddAzureSignalR() (ASP.NET Core の場合) または MapAzureSignalR() (ASP.NET の場合) を呼び出す際にパラメーターとして使用することもできます。

コード例を次に示します。

ASP.NET Core:

services.AddSignalR()
        .AddAzureSignalR(options => options.Endpoints = new ServiceEndpoint[]
        {
            new ServiceEndpoint("<connection_string1>", EndpointType.Primary, "region1"),
            new ServiceEndpoint("<connection_string2>", EndpointType.Secondary, "region2"),
        });

ASP.NET:

app.MapAzureSignalR(GetType().FullName, hub,  options => options.Endpoints = new ServiceEndpoint[]
    {
        new ServiceEndpoint("<connection_string1>", EndpointType.Primary, "region1"),
        new ServiceEndpoint("<connection_string2>", EndpointType.Secondary, "region2"),
    };

複数のプライマリまたはセカンダリ インスタンスを構成できます。 プライマリおよび/またはセカンダリのインスタンスが複数ある場合、ネゴシエートは次の順序でエンドポイントを返します。

  1. 少なくとも 1 つのプライマリ インスタンスがオンラインになっている場合は、ランダムなオンラインのプライマリ インスタンスを返します。
  2. すべてのプライマリ インスタンスがダウンしている場合は、ランダムなオンラインのセカンダリ インスタンスを返します。

Azure Functions で構成する

この記事を参照してください。

フェールオーバーのシーケンスとベスト プラクティス

以上で、適切なシステム トポロジのセットアップが完了しました。 一方の SignalR Service インスタンスがダウンすると、オンライン トラフィックが別のインスタンスにルーティングされます。 プライマリ インスタンスがダウン (およびその後しばらくしてから復旧) したときに発生する状況を以下に示します。

  1. プライマリ サービス インスタンスがダウンすると、このインスタンスにおけるすべてのサーバー接続が切断されます。
  2. このインスタンスは、そこに接続されているすべてのサーバーによってオフラインとしてマークされます。また、ネゴシエートでこのエンドポイントは返されなくなり、セカンダリのエンドポイントが返されるようになります。
  3. また、このインスタンスに対するクライアント接続もすべて閉じられ、クライアントの再接続が行われます。 以後アプリ サーバーからはセカンダリ エンドポイントが返されるので、クライアントはセカンダリ インスタンスに接続されます。
  4. これですべてのオンライン トラフィックがセカンダリ インスタンスに向かうようになりました。 セカンダリはすべてのアプリ サーバーに接続されているため、サーバーからクライアントへのメッセージは依然としてすべて配信されます。 しかし、クライアントからサーバーへのメッセージのルーティング先は、同じリージョン内のアプリ サーバーに限られます。
  5. プライマリ インスタンスが復旧してオンラインに戻った後、アプリ サーバーはプライマリ インスタンスへの接続を再度確立し、それをオンラインとしてマークします。 ネゴシエートでは再びプライマリ エンドポイントが返されるようになるので、新しいクライアントは元どおりプライマリに接続されます。 ただし、既存のクライアントは切断されず、自ら切断するまでそのままセカンダリにルーティングされます。

以下の図は、SignalR サービスにおけるフェールオーバーの動作を示したものです。

図.1 フェールオーバー前 Before Failover

図.2 フェールオーバー後 After Failover

図.3 プライマリの復旧後間もなく Short time after primary recovers

正常時には、オンライン トラフィック (青色) がプライマリのアプリ サーバーと SignalR サービスにのみ向かうことがわかります。 フェールオーバー後は、セカンダリのアプリ サーバーと SignalR サービスもアクティブになります。 プライマリの SignalR サービスがオンラインに戻った後、新しいクライアントはプライマリの SignalR に接続されます。 一方、既存のクライアントはそのままセカンダリに接続された状態になるので、両方のインスタンスにトラフィックが向かうことになります。 既存のクライアントがすべて切断されると、システムが正常な状態に戻ります (図 1)。

リージョンをまたぐ高可用性アーキテクチャを導入する場合、主に次の 2 つのパターンがあります。

  1. 1 つ目は、アプリ サーバーと SignalR サービス インスタンスから成る一方のペアですべてのオンライン トラフィックを処理し、もう一方のペアはバックアップとして使用する方法です (これは "アクティブ/パッシブ" と呼ばれます。図1 を参照)。
  2. もう 1 つは、アプリ サーバーと SignalR サービス インスタンスから成るペアを 2 つ (またはそれ以上) 用意し、それぞれのペアがオンライン トラフィックを分担して処理し、他のペアのバックアップとして機能する方法です (これは "アクティブ/アクティブ" と呼ばれます。図 3 と同様)。

SignalR サービスは両方のパターンに対応できます。主な違いはアプリ サーバーの導入方法です。 アプリ サーバーがアクティブ/パッシブである場合、SignalR Service もアクティブ/パッシブになります (プライマリのアプリ サーバーから返されるのはそのプライマリ SignalR Service インスタンスのみであるため)。 アプリ サーバーがアクティブ/アクティブである場合、SignalR Service もアクティブ/アクティブになります (すべてのアプリ サーバーから、それぞれのプライマリ SignalR インスタンスが返されるので、そのすべてでトラフィックを受けることができます)。

どちらのパターンを使用するにしても、アプリ サーバーには、それぞれの SignalR Service インスタンスをプライマリとして接続する必要がある点に注意してください。

また、SignalR 接続 (長時間接続) の性質上、障害とフェールオーバーが発生すると、クライアントでは接続の切断が生じます。 そのようなケースはクライアント側で処理して、エンド カスタマーからは見えないようにする必要があります。 たとえば、接続が閉じられた後で再接続を行うことが考えられます。

フェールオーバーをテストする方法

フェールオーバーをトリガーするには、次の手順に従います。

  1. ポータルのプライマリ リソースの [ネットワーク] タブで、パブリック ネットワーク アクセスを無効にします。 リソースでプライベート ネットワークが有効になっている場合は、"アクセス制御ルール" を使用して、すべてのトラフィックを拒否します。
  2. プライマリ リソースを再起動します

次のステップ

この記事では、SignalR サービスの回復性を実現するようにアプリケーションを構成する方法について説明しました。 SignalR サービスにおける接続のルーティングとサーバー/クライアント接続の詳細については、SignalR サービスの内部について説明したこちらの記事を参照してください。

大量の接続を処理するために複数のインスタンスを同時に使用するスケーリング シナリオ (シャーディングなど) については、複数のインスタンスをスケーリングする方法に関するページを参照してください。

複数の SignalR サービス インスタンスで Azure Functions を構成する方法の詳細については、 Azure Functions での複数の Azure SignalR サービス インスタンスのサポートに関する記事を参照してください。