SignalR 1.x 的向外延展簡介

作者: Patrick Fletcher

警告

本檔不適用於最新版的 SignalR。 請查看ASP.NET Core SignalR

一般而言,有兩種方式可調整 Web 應用程式: 相應增加相應放大

  • 相應增加表示使用較大的伺服器 (或較大的 VM) 具有更多 RAM、CPU 等。
  • 相應放大表示新增更多伺服器來處理負載。

相應增加的問題在於您快速達到機器大小的限制。 除此之外,您必須相應放大。不過,當您相應放大時,用戶端可以路由傳送至不同的伺服器。 連線至一部伺服器的用戶端將不會接收從另一部伺服器傳送的訊息。

當伺服器向外延展時,用戶端所面臨的問題螢幕擷取畫面是,因為它已連線到一部伺服器,所以不會接收從另一部伺服器傳送的訊息。

其中一個解決方案是使用稱為 背板的元件,在伺服器之間轉送訊息。 啟用後板後,每個應用程式實例都會將訊息傳送至背板,而後板會將訊息轉送至其他應用程式實例。 (在電子中,背板是一組平行連接器。藉由類比,SignalR 背板會連接多部 servers.)

解決方案的螢幕擷取畫面,此解決方案會使用稱為背板的元件在伺服器之間轉送訊息。

SignalR 目前提供三個背板:

  • Azure 服務匯流排。 服務匯流排是一種傳訊基礎結構,可讓元件以鬆散結合的方式傳送訊息。
  • Redis。 Redis 是記憶體內部索引鍵/值存放區。 Redis 支援發佈/訂閱 (「pub/sub」) 模式來傳送訊息。
  • SQL Server。 SQL Server背板會將訊息寫入 SQL 資料表。 背板會使用 Service Broker 進行有效率的傳訊。 不過,如果 Service Broker 未啟用,它也會運作。

如果您在 Azure 上部署應用程式,請考慮使用Azure 服務匯流排背板。 如果您要部署至自己的伺服器陣列,請考慮SQL Server或 Redis 背板。

下列主題包含每個背板的逐步教學課程:

實作

在 SignalR 中,每個訊息都會透過訊息匯流排傳送。 訊息匯流排會實作 IMessageBus 介面,以提供發佈/訂閱抽象概念。 背板的運作方式是將預設 IMessageBus 取代為專為該背板設計的匯流排。 例如,Redis 的訊息匯流排是 RedisMessageBus,它會使用 Redis pub/sub 機制來傳送和接收訊息。

每一個伺服器實例都會透過匯流排連線到背板。 當訊息傳送時,它會傳送至背板,而後板會將它傳送至每部伺服器。 當伺服器從背板取得訊息時,會將訊息放在其本機快取中。 然後,伺服器會從其本機快取將訊息傳遞至用戶端。

針對每個用戶端連線,會使用資料指標來追蹤讀取訊息資料流程的用戶端進度。 (資料指標代表訊息資料流程中的位置。) 如果用戶端中斷連線,然後重新連線,它會要求匯流排輸入用戶端資料指標值之後抵達的任何訊息。 當連線使用 長輪詢時,就會發生相同的情況。 長時間輪詢要求完成之後,用戶端會開啟新的連線,並要求在游標之後抵達的訊息。

即使用戶端在重新連線時路由至不同的伺服器,資料指標機制仍可運作。 背板知道所有伺服器,而且用戶端所連線的伺服器並不重要。

限制

使用背板時,訊息輸送量上限會低於用戶端直接與單一伺服器節點通訊時。 這是因為背板會將每個訊息轉送至每個節點,因此背板可能會成為瓶頸。 此限制是否為問題,取決於應用程式。 例如,以下是一些典型的 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>