SignalR傳輸效能評測-雙向傳輸

上回測過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決定傳輸方式的邏輯如下: (參考)

  1. IE6/7/8? 直接保送Long Polling (這又給了我們一個不該用老IE的好理由)
    【2013-12-06更新】依據官方文件,SignalR 2.0僅支援IE8+,感謝ChrisTorng補充
  2. 若啟動連線時指定了JSONP參數 –> Long Polling
  3. 如果SignlaR連線對象為跨網域,且滿足以下情境,將採WebSocket,否則用Long Polling
    * Client支援CORS
    * Client支援WebSocket
    * Server支援WebSocket
  4. 若未指定JSONP參數且Server/Client都支援WebSocket –> WebSocket
  5. 若Client或Server端不支援WebSocket,但支援Server Sent Event –> Server Sent Event
  6. 如果前述Server Sent Event不可用,改用Forever Frame
  7. 如果前述Forever Frame也失敗,改用Long Polling
歡迎推文分享:
Published 05 December 2013 05:30 AM 由 Jeffrey
Filed under:
Views: 12,634



意見

# ChrisTorng said on 04 December, 2013 08:03 PM

我有看到原文的 If the browser is Internet Explorer 8 or earlier, Long Polling is used。

不過在 Supported Platforms www.asp.net/.../supported-platforms 也有明確列出,僅支援 IE8 以上...

更精確地說,在 our testing matrix testswarm.signalr.net/.../signalr 內,最新的 496edbde69 testswarm.signalr.net/.../556 中,列出支援 IE8 搭配 jQuery 1.6.4/jQuery 1.9.1,但不支援 jQuery 2.0.0,而 IE9 則支援上述三個 jQuery 版本。

# Jeffrey said on 05 December, 2013 08:04 PM

to ChrisTorng, 謝謝補充,已加入本文。

# SAM said on 06 December, 2013 07:32 AM

請問黑大可否讓小弟我轉在FB上?感謝萬分,辛苦您了。

# Jeffrey said on 06 December, 2013 09:24 AM

to SAM, 歡迎轉發,註明出處即可。

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<December 2013>
SunMonTueWedThuFriSat
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234
 
RSS
創用 CC 授權條款
【廣告】
twMVC
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication