2021-05-12 14:32:11
jmeter測試基於SignalR的Websocket過程中的一些總結
引言
ASP.NET Core SignalR 作為微軟官方出品的一個實時Web中介軟體功能庫,可以使伺服器端程式碼可以將內容立即推播到使用者端。
SignalR supports the following techniques for handling real-time communication (in order of graceful fallback):
- WebSockets
- Server-Sent Events
- Long Polling
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
其他參考
相關文章