前言
如果 WebSocket 伺服器頻繁向客戶端發送訊息,是否會影響客戶端的請求?是否應該使用多個 WebSocket 連接來分開數據流量?所以我用 Golang 來做這個場景的基準測試。最後,讓我來和大家分享一下這個結果。
Benchmark 目標
當伺服器通過 WebSocket 連線以高頻率向客戶端發送數據時,如果客戶端通過同一 WebSocket 連線向伺服器發送低頻率信息,需要多長時間才能收到回覆?
原始碼與使用方法
- 原始碼: websocket-stream-benchmarck
使用方法:
Clone 此專案並編譯1
2
3git clone https://github.com/weirenxue/websocket-stream-benchmarck.git # clone
make # build將會在
./bin
文件夾中找到兩個可執行文件client
和server
。首先運行./bin/server
,然後打開另一個終端窗口,運行./bin/client
,等待client
完成執行並輸出結果。你可能想改變
config.toml
中的配置,看看不同情況下的測試結果。
config.toml 的參數說明
server
host
:WebSocket 伺服器主機。port
:WebSocket 伺服器端口。dummy_message_size
:每個假訊息的大小。dummy_message_duration
:發送每個假訊息的時間間隔。
client
request_duration
:發送每個請求的時間間隔。total_request
:應該發送的請求的數量。
設計概念
- Server:一旦客戶端連接到伺服器,伺服器就會每隔
dummy_message_duration
向客戶端發送一條大小為dummy_message_size
的訊息。伺服器會監聽客戶端是否發送訊息,如果是,它將接收並直接回覆原始訊息。 - Client:客戶端生成一個
uuid
作為發送給伺服器的請求,而伺服器必須發回同樣的訊息。基於uuid
的唯一性,我們可以知道一個請求從被發送到被回覆所需的時間,最後將每個請求所需的時間除以請求的數量以取得平均來回時間。
最後,每個案例測試五次,選擇最差的案例並記錄在實驗結果中。
測試環境與結果
- OS:macOS 12.2.1
- CPU:i7 2.7GHz 4 Cores
- RAM:16 GB LPDDR3
dummy config→ request config↓ |
dummy_message_size="10KB" dummy_message_duration="1h" (no dummy message due to long duration) |
dummy_message_size="10KB" dummy_message_duration="500us" |
dummy_message_size="1MB" dummy_message_duration="500us" |
---|---|---|---|
total_request=1000 request_duration="1ms" |
total duration: 160.714504ms average duration: 160.714µs total received dummy message: 0B |
total duration: 83.472281ms average duration: 83.472µs total received dummy message: 19710KB |
total duration: 5.364239748s average duration: 5.364239ms total received dummy message: 787MB |
request_duration="10ms" total_request=1000 |
total duration: 300.998294ms average duration: 300.998µs total received dummy message: 0B |
total duration: 110.638204ms average duration: 110.638µs total received dummy message: 154350KB |
total duration: 5.675233495s average duration: 5.675233ms total received dummy message: 7520MB |
結語
我們也許會擔心若所有資料流量都在同一個 WebSocket 連線上,頻寬會被分走,導致有些 Client 端的指令無法被及時處理。但根據這個專案的結果顯示,我們可以放心的讓所有資料流量都在一個 WebSocket 連線上傳遞。這是好事,因為多個連線會造成伺服器一定的負擔。
除此之外,可以從商用產品來看 WebSocket 連線數問題。例如,在 Firebase 的 Realtime Database 服務的官方定價中,有一項是限制同時使用的連線數,因此若在一個瀏覽器視窗上有多個連線數,將會造成金額上的負擔。當然,Firebase SDK 很貼心,讓所有的請求都是在同一個 WebSocket 上進行,以確保一個瀏覽器視窗只有一個 WebSocket 連線。