EarthChat SignalR原理講解

tokengo發表於2023-09-26

SignalR原理講解

SignalR是什麼?

SignalR 是 Microsoft 開發的一個庫,用於 ASP.NET 開發人員實現實時 web 功能。這意味著服務端程式碼可以實時地推送內容到連線的客戶端,而不需要客戶端定期請求或輪詢伺服器以獲取新資料。SignalR 可以用於各種應用程式,如實時聊天、通知、實時資料更新等。

SignalR 提供了以下特點:

  1. 抽象層的連線:SignalR 提供了一種高階API,隱藏了底層實時通訊的複雜性。開發者不需要擔心具體使用 WebSockets、Server-Sent Events、長輪詢等,因為 SignalR 會根據客戶端和伺服器的能力自動選擇最佳的通訊方式。

  2. 連線管理:自動處理連線、重連和斷開連線的複雜性。

  3. 組播:可以廣播訊息到所有連線的客戶端,或者只給特定的客戶端或客戶端組傳送訊息。

  4. 擴充套件性:支援可插拔的元件,允許開發者自定義或擴充套件其功能。

  5. 跨平臺:除了在網頁客戶端上使用,還提供了客戶端庫支援各種平臺,如 .NET、JavaScript、Java、Swift 和 Objective-C 等。

要使用 SignalR,開發者需要安裝相應的 NuGet 包並按照文件中的指導進行配置和開發。

在近幾年,SignalR 核心 (SignalR Core) 成為了主流,它是為 .NET Core 重新設計和實現的 SignalR 版本,提供了更好的效能和跨平臺支援。

SignalR MessagePack

什麼是 MessagePack?

MessagePack
是一種快速而緊湊的二進位制序列化格式。 當擔憂效能和頻寬問題時,這很有用,因為它建立的訊息比 JSON 建立的小。 檢視網路跟蹤和日誌時,二進位制訊息不可讀取,除非這些位元組是透過 MessagePack 分析器傳遞的。 SignalR 為 MessagePack 格式提供內建支援,並提供 API 供客戶端和伺服器使用。

在伺服器上配置 MessagePack

若要在伺服器上啟用 MessagePack 中心協議,請在應用中安裝 Microsoft.AspNetCore.SignalR.Protocols.MessagePack 包。 在 Startup.ConfigureServices 方法中,將 AddMessagePackProtocol 新增到 AddSignalR 呼叫以在伺服器上啟用 MessagePack 支援。

services.AddSignalR()
    .AddMessagePackProtocol();

:::info 小知識

JSON 預設啟用。 新增 MessagePack 可同時支援 JSON 和 MessagePack 客戶端。

:::

當啟用了MessagePack,客戶端會傳送協議訊息和版本

{"protocol":"messagepack","version":1}

後續會使用二進位制傳輸,

:::tip 小知識

MessagePack在序列化中對比json序列化效能更好,並且體積更小,所以用於作為訊息傳輸再合適不過了,但它不適合作為可讀性的格式,所以在某些不需要可讀性,需要效能的場景更合適。

:::

如何使用SignalR進行橫向擴充套件

首先講一下什麼是橫向擴充套件

橫向擴充套件(Horizontally Scaling),也常稱為“擴充套件出”或“擴充套件寬”,是一種增加系統容量的方法,透過在現有的硬體叢集中新增更多的機器或節點來實現。與之相對的是縱向擴充套件(Vertically Scaling)或稱為“擴充套件高”,它涉及增加單一機器的資源,如CPU、RAM或儲存。

橫向擴充套件的主要特點和優勢:

  1. 彈性擴充套件:能夠根據需求動態地新增或減少節點,這在雲端計算環境中特別受歡迎。
  2. 容錯性:由於存在多個節點,即使某個節點出現故障,系統也可以繼續執行。
  3. 負載分散:請求可以在多個伺服器或節點之間進行分配,避免了單一節點的瓶頸。
  4. 通常更經濟:與購買一個大型、昂貴的超級伺服器相比,購買多臺中低規格的機器往往更為經濟。

總的來說,當我們的單體伺服器無法支撐我們現有使用者的時候,只需要在新增節點便可支援更多使用者。但是橫向擴充套件也一樣會有缺點,

  1. 複雜性:管理和維護多個節點可能會比維護一個高效能的節點更加複雜。
  2. 資料一致性:在多個節點上分散資料可能導致資料同步和一致性問題。
  3. 網路開銷:節點間的通訊可能增加網路延遲。
  4. 軟體相容性:並不是所有軟體都能輕鬆地進行橫向擴充套件,某些應用可能需要特定的設計或配置。

為什麼要實現橫向擴充套件

由於一個伺服器的資源是有限的,雖然說在使用的時候並沒有達到硬體的上線但也存在Tcp連線數的限制,以下是官方介紹

Web 伺服器可以支援的併發 TCP 連線數受到限制。 標準 HTTP 客戶端使用臨時連線。 這些連線可以在客戶端進入空閒狀態時關閉,並在以後重新開啟。 另一方面,SignalR 連線是永續性的。 SignalR 連線即使在客戶端進入空閒狀態時也保持開啟狀態。 在為許多客戶端提供服務的高流量應用中,這些永續性連線可能會導致伺服器達到其最大連線數。

永續性連線還會佔用一些額外記憶體來跟蹤每個連線。

SignalR 大量使用連線相關資源可能會影響在同一伺服器上託管的其他 Web 應用。 SignalR 開啟並保持最後一個可用 TCP 連線時,同一伺服器上其他 Web 應用也不再有可用連線。

如果伺服器的連線用完,則你會看到隨機套接字錯誤和連線重置錯誤。 例如:

複製

An attempt was made to access a socket in a way forbidden by its access permissions...

若要防止 SignalR 資源使用在其他 Web 應用中導致錯誤,請在與其他 Web 應用不同的伺服器上執行 SignalR。

若要防止 SignalR 資源使用在 SignalR 應用中導致錯誤,請橫向擴充套件以限制伺服器必須處理的連線數。

Signalr是如何實現橫向擴充套件的?

SignalR 透過一種稱為“後端”或“後臺”儲存的機制實現橫向擴充套件。在 SignalR 中,為了支援跨多個伺服器或節點的連線和訊息傳遞,需要一箇中心的後臺儲存來確保訊息在所有伺服器之間都能正確地傳遞。

以下是 SignalR 實現橫向擴充套件的幾種常見方式:

  1. Redis 後端:Redis 是一個非常受歡迎的鍵值儲存,SignalR 可以使用 Redis 作為後臺儲存來支援其橫向擴充套件。當 SignalR 使用 Redis 時,所有的 SignalR 伺服器都連線到同一個 Redis 例項或叢集,並使用 Redis 的釋出/訂閱功能來傳遞訊息。
  2. SQL Server 後端:SignalR 也支援使用 SQL Server 作為後臺儲存,但這種方式的效能和可擴充套件性可能不如 Redis。
  3. Azure Service Bus 後端:對於在 Azure 上執行的 SignalR 應用程式,Azure Service Bus 可以作為一個後臺儲存選項。
  4. 自定義後端儲存:開發人員也可以為 SignalR 建立自定義的後端儲存解決方案。

當 SignalR 使用後端儲存進行橫向擴充套件時,以下幾點是需要考慮的:

  • 負載均衡:要確保所有的 SignalR 伺服器之間的客戶端連線請求能夠均勻分配。
  • 伺服器親和性:在某些情況下,可能需要確保客戶端總是連線到同一個 SignalR 伺服器,這稱為“伺服器親和性”或“會話親和性”。但是,當使用後端儲存如 Redis 時,這種親和性往往不是必需的,因為所有的伺服器都可以接收並廣播訊息。
  • 資源和成本:後端儲存引入了額外的資源和成本,尤其是當使用付費服務(如 Azure Service Bus)或需要管理和維護的服務(如 Redis 或 SQL Server)時。

Redis橫向擴充套件

SignalR 使用 Redis 作為後端儲存來實現橫向擴充套件的方式是基於 Redis 的釋出/訂閱 (pub/sub) 功能。這使得在多個 SignalR 伺服器例項之間同步和傳遞訊息成為可能。以下是 SignalR 如何使用 Redis 實現橫向擴充套件的過程:

  1. 連線到 Redis:每個 SignalR 伺服器例項在啟動時都會與配置好的 Redis 伺服器或叢集建立連線。
  2. 訂閱:SignalR 伺服器例項使用 Redis 的釋出/訂閱功能進行訂閱。每當有一個新的 SignalR 叢集加入時,它都會訂閱相關的通道,以便接收訊息。
  3. 釋出訊息:當一個 SignalR 伺服器例項需要傳送訊息給它的客戶端時(這可能是因為一個客戶端向另一個客戶端傳送訊息,而這兩個客戶端可能連線到不同的伺服器例項),該伺服器例項會將訊息釋出到 Redis。
  4. 接收訊息:由於所有 SignalR 伺服器例項都訂閱了 Redis 的通道,因此它們都會接收到該訊息。收到訊息的每個伺服器例項都會檢查該訊息是否針對其上的任何客戶端,如果是,則將訊息轉發給這些客戶端。
  5. 負載均衡:在使用 Redis 進行橫向擴充套件時,還需要一個負載均衡器來確保新的客戶端連線請求在所有 SignalR 伺服器例項之間進行均衡分配。這樣,不同的客戶端可能連線到不同的伺服器例項。
  6. 持久連線和組:SignalR 的 Redis 後端不僅支援持久連線(如 Hubs)的訊息傳遞,還支援分組操作。例如,如果你在一個伺服器例項上將客戶端加入一個特定的組,並且稍後想向該組傳送訊息,即使傳送請求來自另一個伺服器例項,Redis 也能確保訊息正確地傳送給該組的所有成員。

要使用 Redis 作為 SignalR 的後端儲存,開發者需要安裝相應的 SignalR Redis 包,並在應用程式的配置中指定 Redis 作為後端儲存。

總的來說,透過使用 Redis 的釋出/訂閱功能,SignalR 能夠在多個伺服器例項之間同步和傳遞訊息,從而實現橫向擴充套件。

SqlServer橫向擴充套件

SignalR 使用 SQL Server 作為後端來實現橫向擴充套件主要是透過 SQL Server 的訊息佇列功能,特別是 SQL Server 的 Service Broker。以下是 SignalR 使用 SQL Server 進行橫向擴充套件的基本原理:

  1. 設定 Service Broker:為了使用 SQL Server 作為 SignalR 的後端,首先需要確保 SQL Server 資料庫啟用了 Service Broker。
  2. 訊息佇列:SignalR 使用 Service Broker 提供的訊息佇列功能。當一個 SignalR 伺服器例項需要廣播訊息到其他伺服器例項時,它會將訊息釋出到 SQL Server 的一個特定佇列中。
  3. 訊息通知:當訊息被放入佇列時,Service Broker 會通知所有訂閱了該佇列的 SignalR 伺服器例項。每個伺服器例項隨後可以從佇列中檢索並處理訊息,然後將其轉發給連線到該例項的客戶端。
  4. 持久化:使用 SQL Server 作為後端的另一個優點是訊息會持久化,這意味著即使所有的 SignalR 伺服器都崩潰,訊息仍然可以在系統恢復後被處理和傳遞。

要使用 SQL Server 作為 SignalR 的後端進行橫向擴充套件,需要進行一些配置:

  • 安裝適當的 NuGet 包,例如 Microsoft.AspNet.SignalR.SqlServer
  • 在 SignalR 的配置中,指定使用 SQL Server 作為後端並提供適當的連線字串。
  • 確保使用的 SQL Server 資料庫啟用了 Service Broker。

儘管 SQL Server 可以作為 SignalR 的後端,並提供了持久化和橫向擴充套件的能力,但使用它可能會引入一些效能考慮。例如,與記憶體中的解決方案(如 Redis)相比,使用 SQL Server 可能會導致更高的延遲。此外,還需要確保 SQL Server 自身具有足夠的效能和資源來處理大量的 SignalR 訊息流量。

EarthChat

一個基於.NET 7實現新版本QQ UI
單機支援十萬人的線上Chat
技術交流群:737776595
Gitee開源:https://gitee.com/hejiale010426/chat
GitHub開源:https://github.com/239573049/chat
專案文件: https://116.196.96.91/docs/intro
提供Asp.NET Core相關知識文件講解

相關文章