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

作成者: Patrick Fletcher

警告

このドキュメントは、SignalR の最新バージョン用ではありません。 SignalR の ASP.NET Coreを見てみましょう。

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

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

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

サーバーがスケールアウトされるときにクライアントが直面する問題のスクリーンショットは、あるサーバーに接続されているため、別のサーバーから送信されたメッセージを受信しないということです。

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

バックプレーンと呼ばれるコンポーネントを使用してサーバー間でメッセージを転送するソリューションのスクリーンショット。

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 メカニズムを使用してメッセージを送受信します。

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

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

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

制限事項

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

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

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

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

<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>