SignalR傳輸效能評測-雙向傳輸
4 |
上回測過SignalR四種傳輸方式的Server到Client段效能表現,確認Long Polling因不斷重發Request效率稍差,其餘兩種方式效能則相去不遠,WebSocket並無格外突出。先前剖析中,我們知道WebSocket最大特色在於"支援雙向傳輸",這回我們來個Server到Client、Client到Server傳輸各半的模擬情境。(WebSocket都做球給你了,好好表現囉~)
規劃以下測試情境: 每次Server送一個Runner到Client後(經由addRunner),Client必須用接收到的Runner資料呼叫Server端AckRunner()方式作為簽收,Server端在收到簽收回饋才算完成一次Round-Trip後,再送出下一筆Runner資料(經由AutoResetEvent實現收到回饋才送下一筆的同步邏輯),這個情境同時考驗接收與傳送兩個方向的效率。
Server端程式新增RoundTripTest()及AckRunner()兩個方法,在RoundTripTest()會在送出Runner後將其RoundTripSync(型別為AutoResetEvent) Reset(),接著WaitOne()等待它被Set();當Client端收到Runner後,呼叫該Server端的AckRunner()方法,其中會執行AutoResetEvent.Set(),使前述WaitOne()被放行,繼續執行下一筆。AckRunner()其實傳入Runner.Id即可,但我想讓Client到Server也傳送相同資料量,故選擇傳入整個Runner物件。
public void RoundTripTest()
{
var caller = Clients.Caller;
Task.Factory.StartNew(() =>
{
foreach (var runner in dataStore.Values)
{
runner.RoundTripSync.Reset();
caller.addRunner(runner);
runner.RoundTripSync.WaitOne();
}
});
}
public void AckRunner(Runner runner)
{
dataStore[runner.Id].RoundTripSync.Set();
}
HTML端修改得不多,只在addRunner()中加入一行marathron.server.ackRunner(runner);
marathron.client.addRunner = function (runner) {
runners.push(runner);
$counter.text(runners.length + "@" + (new Date() - startTime) + "ms");
marathron.server.ackRunner(runner);
if (runner.Name == "Last")
$("#ulDisplay").append("<li>" + $counter.text() + "</li>");
};
實測結果:
- IE10 Forever Frame
3756ms, 3670ms, 3719ms - IE10 Long Polling
8764ms, 8280ms, 8510ms - IE10 WebSocket
2539ms, 1850ms, 2808ms - Chrome Long Polling
3651ms, 3853ms, 3572ms - Chrome Server Sent Event
3245ms, 2995ms, 3167ms - Chrome WebSocket
1575ms, 2215ms, 1123ms
【結論】
一如預期,支援雙向傳送的WebSocket免除1000次呼叫AckRunner()的(/signalr/send) Request,獲得壓倒性勝利! 快了近3倍。而Long Polling原本就不斷地在結束並重開Request,多了額外的1000次/signalr/send Request後,效能慘不忍睹。如此可推論,當Client呼叫Server端的次數愈頻繁,WebSocket就愈佔優勢,而Long Polling輸得愈慘,雖然用什麼傳輸方式取決於瀏覽器與伺服器的支援度,這個結果還是可做為不同情境效能表現的評估參考。
【補充】
SignalR決定傳輸方式的邏輯如下: (參考)
- IE
6/7/8? 直接保送Long Polling (這又給了我們一個不該用老IE的好理由)
【2013-12-06更新】依據官方文件,SignalR 2.0僅支援IE8+,感謝ChrisTorng補充 - 若啟動連線時指定了JSONP參數 –> Long Polling
- 如果SignlaR連線對象為跨網域,且滿足以下情境,將採WebSocket,否則用Long Polling
* Client支援CORS
* Client支援WebSocket
* Server支援WebSocket - 若未指定JSONP參數且Server/Client都支援WebSocket –> WebSocket
- 若Client或Server端不支援WebSocket,但支援Server Sent Event –> Server Sent Event
- 如果前述Server Sent Event不可用,改用Forever Frame
- 如果前述Forever Frame也失敗,改用Long Polling
Comments
# by ChrisTorng
我有看到原文的 If the browser is Internet Explorer 8 or earlier, Long Polling is used。 不過在 Supported Platforms http://www.asp.net/signalr/overview/signalr-20/getting-started-with-signalr-20/supported-platforms 也有明確列出,僅支援 IE8 以上... 更精確地說,在 our testing matrix http://testswarm.signalr.net/user/signalr 內,最新的 496edbde69 http://testswarm.signalr.net/job/556 中,列出支援 IE8 搭配 jQuery 1.6.4/jQuery 1.9.1,但不支援 jQuery 2.0.0,而 IE9 則支援上述三個 jQuery 版本。
# by Jeffrey
to ChrisTorng, 謝謝補充,已加入本文。
# by SAM
請問黑大可否讓小弟我轉在FB上?感謝萬分,辛苦您了。
# by Jeffrey
to SAM, 歡迎轉發,註明出處即可。