次の方法で共有


SignalR 1.x のスケールアウト入門

作成者: Patrick Fletcher

警告

このドキュメントは、最新版の SignalR を対象としていません。 ASP.NET Core SignalR に関する記事を参照してください。

一般に、Web アプリケーションをスケーリングするには、"スケールアップ" と "スケールアウト" の 2 つの方法があります。

  • スケールアップとは、より多くの RAM、CPU などを備えたより大きなサーバー (またはより大きな VM) を使うことを意味します。
  • スケールアウトとは、負荷を処理するためにサーバーを追加することを意味します。

スケールアップの問題は、すぐにマシンのサイズの制限に達してしまうことです。 それを超えるには、スケールアウトする必要があります。ただし、スケールアウトすると、クライアントは異なるサーバーにルーティングされる可能性があります。 あるサーバーに接続されているクライアントは、別のサーバーから送信されたメッセージを受信しません。

Screenshot of the issue a client faces when a server is scaled out is that since it is connected to one server it will not receive messages sent from another server.

1 つの解決策は、"バックプレーン" というコンポーネントを使って、サーバー間でメッセージを転送することです。 バックプレーンが有効になっている場合、各アプリケーション・インスタンスはメッセージをバックプレーンに送信し、バックプレーンがメッセージを他のアプリケーション・インスタンスに転送します。 (エレクトロニクスでは、バックプレーンは並列コネクタのグループです。たとえば、SignalR バックプレーンでは複数のサーバーを接続します)

Screenshot of the solution to forward messages between servers using a component called a backplane.

SignalR には、現在、次の 3 つのバックプレーンが用意されています。

  • Azure Service Bus。 Service Bus は、コンポーネントが疎結合の方法でメッセージを送信できるようにするメッセージング インフラストラクチャです。
  • Redis。 Redis は、メモリ内のキー値ストアです。 Redis では、メッセージを送信するためのパブリッシュ/サブスクライブ ("pub/sub") パターンがサポートされています。
  • SQL Server。 SQL Server バックプレーンは、SQL テーブルにメッセージを書き込みます。 このバックプレーンは Service Broker を使用して効率的なメッセージングを行います。 ただし、Service Broker が有効になっていない場合にも機能します。

Azure にアプリケーションをデプロイする場合は、Azure Service Bus バックプレーンの使用を検討してください。 独自のサーバー ファームにデプロイする場合は、SQL Server または Redis バックプレーンを検討してください。

次のトピックには、各バックプレーンの段階的なチュートリアルが含まれています。

実装

SignalR では、すべてのメッセージがメッセージ バスを通じて送信されます。 メッセージ バスは、パブリッシュ/サブスクライブの抽象化を提供する IMessageBus インターフェイスを実装します。 バックプレーンは、デフォルトの IMessageBus をそのバックプレーン用に設計されたバスに置き換えることで機能します。 たとえば、Redis のメッセージ バスは RedisMessageBus で、Redis pub/sub メカニズムを使ってメッセージを送受信します。

各サーバー インスタンスは、バスを介してバックプレーンに接続します。 メッセージが送信されると、それはバックプレーンに送られ、バックプレーンはそれをすべてのサーバーに送信します。 サーバーはバックプレーンからメッセージを受信すると、そのメッセージをローカル キャッシュに保持します。 その後、サーバーはローカル キャッシュからクライアントにメッセージを配信します。

クライアント接続ごとに、メッセージ ストリームの読み取りにおけるクライアントの進行状況が、カーソルを使って追跡されます (カーソルはメッセージ ストリーム内の位置を表します)。クライアントが切断してから再接続すると、クライアントのカーソル値の後に到着したメッセージをバスに要求します。 接続で長いポーリングを使う場合も同じことが発生します。 長いポーリング要求が完了すると、クライアントは新しい接続を開き、カーソルの後に到着したメッセージを要求します。

カーソル メカニズムは、再接続時にクライアントが別のサーバーにルーティングされた場合でも機能します。 バックプレーンはすべてのサーバーを認識しており、クライアントがどのサーバーに接続するかは関係ありません。

制限事項

バックプレーンを使うと、最大メッセージ スループットは、クライアントが単一サーバー ノードと直接通信する場合よりも低くなります。 これは、バックプレーンがすべてのメッセージをすべてのノードに転送するため、バックプレーンがボトルネックになる可能性があるためです。 この制限が問題になるかどうかはアプリケーションによって異なります。 たとえば、一般的な SignalR シナリオをいくつか次に示します。

  • サーバー ブロードキャスト (ストック ティッカーなど): サーバーがメッセージの送信速度を制御するため、このシナリオではバックプレーンが適切に機能します。
  • クライアント間 (チャットなど): このシナリオでは、メッセージの数がクライアントの数に応じてスケーリングする場合、つまり、より多くのクライアントが参加するにつれてメッセージのレートが比例して増加する場合、バックプレーンがボトルネックになる可能性があります。
  • 高頻度リアルタイム (リアルタイム ゲームなど): このシナリオでは、バックプレーンは推奨されません。

SignalR スケールアウトのトレースの有効化

バックプレーンのトレースを有効にするには、web.config ファイルのルートの configuration 要素の下に次のセクションを追加します。

<configuration>
  <system.diagnostics>
    <sources>
      <source name="SignalR.SqlMessageBus">
        <listeners>
          <add name="SignalR-Bus" />
        </listeners>
      </source>
      <source name="SignalR.ServiceBusMessageBus">
        <listeners>
          <add name="SignalR-Bus" />
        </listeners>
      </source>
      <source name="SignalR.ScaleoutMessageBus">
        <listeners>
          <add name="SignalR-Bus" />
        </listeners>
      </source>
    </sources>
    <switches>
      <add name="SignalRSwitch" value="Verbose" />
      <!-- Off, Critical, Error, Warning, Information, Verbose -->
    </switches>
    <sharedListeners>
      <add name="SignalR-Bus" 
          type="System.Diagnostics.TextWriterTraceListener" 
          initializeData="bus.log.txt" />
    </sharedListeners>
    <trace autoflush="true" />
  </system.diagnostics>
  . . .
</configuration>