首頁 > 軟體

jmeter測試基於SignalR的Websocket過程中的一些總結

2021-01-05 14:00:18

引言

ASP.NET Core SignalR 作為微軟官方出品的一個實時Web中介軟體功能庫,可以使伺服器端程式碼可以將內容立即推播到使用者端。

SignalR supports the following techniques for handling real-time communication (in order of graceful fallback):

SignalR automatically chooses the best transport method that is within the capabilities of the server and client.

背景

​ 在使用jmeter對自己搭建的聊天服務(訊息轉發服務)進行壓力測試的時候,發現和傳統的websocket連線測試過程不同,比如websocket連線地址是什麼,埠是什麼,這些都不是signalr去暴露出來的,因此進入了深一步的研究。

​ 通俗來講,SignalR只是一個實時Web的中介軟體,它支援的通訊模式有WebSocketsSSELong Polling ,目前我們只考慮最優的websocket模式,那麼它的websocket地址是什麼呢?

​ 因為我是將SignalR中介軟體寄宿於Web MVC中,然後部署在Linux下,所以這裡websocket的地址就是 127.0.0.1/chatHub ,後面的名稱,具體的路由地址,看你再starup.cs中如何對映SignalR請求地址和後臺中的Hub名稱。

過程分析

通過web端監控,發現連線使用者端連線SignalR會執行兩個步驟

negotiate

返回的結果,注意看下這個connectionToken ,這個token會作為 一個引數在接下來的chatHub中去請求伺服器。

{
  "negotiateVersion": 1,
  "connectionId": "eZuczhINi9cewADWJO4kXA",
  "connectionToken": "SZyT2pHeOXXNaCrveIJx5A",
  "availableTransports": [
    {
      "transport": "WebSockets",
      "transferFormats": [
        "Text",
        "Binary"
      ]
    },
    {
      "transport": "ServerSentEvents",
      "transferFormats": [
        "Text"
      ]
    },
    {
      "transport": "LongPolling",
      "transferFormats": [
        "Text",
        "Binary"
      ]
    }
  ]
}

原始碼檔案的描述中可以看出,如果在請求的時候,沒有傳送negotiateVersion這個引數,它會預設為0,且此時返回的資料中是沒有connectionToken這個引數的。

並且在連線websocket的時候,如果對id這個引數賦值的話,如果它是錯誤的,會提示你無法連線,但是如果你不傳這個id,它其實是可以連線上的。

連線websocket-->chatHub

WebSockets傳輸是唯一的,因為它是全雙工的,並且可以在單個操作中建立持久連線。結果,不需要使用者端使用該POST [endpoint-base]/negotiate請求來預先建立連線。它還在其自己的幀後設資料中包含所有必需的後設資料。

通過建立與WebSocket的連線來啟用WebSocket傳輸[endpoint-base]。該可選的 id查詢字串值被用來識別附加到連線。如果沒有id查詢字串值,則建立新連線。如果指定了引數,但沒有與指定ID值的連線,404 Not Found則返回響應。收到此請求後,將建立連線,並且伺服器將101 Switching Protocols立即通過WebSocket升級()進行響應,以準備傳送/接收幀。WebSocket OpCode欄位用於指示幀的型別(文字或二進位制)。

如果已經存在與端點連線關聯的WebSocket連線,則不允許建立第二個WebSocket連線,並且將失敗,並顯示409 Conflict狀態程式碼。

建立連線時的錯誤通過返回500 Server Error狀態碼作為對升級請求的響應來處理。這包括初始化EndPoint型別的錯誤。未處理的應用程式錯誤會觸發WebSocketClose框架,其原因碼與規範中的錯誤相匹配(對於錯誤訊息(例如訊息過大或無效的UTF-8))。對於連線過程中的其他意外錯誤,將使用非1000 Normal Closure狀態程式碼。

jmeter設定

1.negotitate請求

2.開啟websocket連線

3.傳送webscoket資料

在SignalR中,總是要從使用者端傳送的第一幀是HandshakeRequest {「 protocol」:「 json」,「 version」:1}

4.新增websocket心跳機制

SignalR的心跳機制是底層自動傳送的,而且使用者端和伺服器端並不會構成實時響應,就類似於,伺服器端和使用者端兩者分別自己傳送心跳,我們模擬一個使用者端的傳送心跳

這個使用jmeter的Sampler-->websocket Single Write Sampler 新增即可,保持與websocket連線,傳送內容為 {"type":6}

5.其他

  • 基於SignalR的websocket在模擬測試傳送訊息的時候,都需要在後面新增一個特殊符號,我們可以從web頁面F12中【NetWork】裡抓取這個特殊符號。
  • jmeter中的websocket元件似乎針對廣播模式的場景支援不太友好,因為廣播模式下,使用者端不知道什麼時候會收到伺服器端的訊息,或者說會一直收到伺服器端的訊息(並行人數夠多的時候),而如果此時沒有讀取websocket中的(通道中)的訊息,可能會造成網路堵塞,然後測試用例就開始出現異常,從而出現連線斷開

不使用 SignalR 的 WebSocket

微軟官方也提供了不使用 SignalR 的 WebSocket的方法,有興趣的小夥伴可以研究下:

https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/websockets?view=aspnetcore-5.0

其他參考


IT145.com E-mail:sddin#qq.com