【譯】Node.js的速度困境:AJAX 和 Socket.IO到底選哪一個?

翻譯:瘋狂的技術宅
原文標題:A Node.js speed dilemma: AJAX or Socket.IO?
原文連接:http://www.cubrid.org/blog/no...
本文首發微信公衆號:充實的腦洞。轉載需註明出處!javascript

當我開始本身的第一個Node.js項目時,我發現的第一件事就是如何處理瀏覽器(客戶端)和中間件之間的通訊(中間件是用CUBRID Node.js驅動編寫的(node-cubrid)的Node.js應用與CUBRID 8.4.1數據庫交換信息)。html

我已經很是熟悉AJAX了,可是在學習Node.js時,我發現了Socket.IO模塊,甚至在互聯網上發現了一些很是不錯的代碼示例... 很是好用(重用)...java

所以,這很快成爲一個難題:應該選哪一個,Ajax仍是sockets.io?node

顯然,因爲個人經驗很是有限,因此我須要更多的信息。換句話說,應該好好的Google一番 :)jquery

顯然相關的信息很是多,可是須要過濾掉那些沒用的 "噪音",並獲得真正有用的東西。讓我跟你們分享一下關於這個話題的一些連接:web

總而言之,這是我發現的:

  1. Socket.IO(一般)用的是客戶端和服務器(中間件)之間的持續鏈接,所以你會達到服務器端資源所容許的併發鏈接數上限(而相同的資源能夠支持更多的AJAX異步請求)。

  2. 使用AJAX,你能夠請求RESTful接口。這意味着您能夠利用現有的 HTTP 服務,例如:代理緩存請求和帶條件的GET請求。

  3. 與 Socket.IO 相比,AJAX 有更多(通訊)數據開銷(例如:HTTP頭,Cookie等)。

  4. AJAX一般比Socket.IO快 ...

  5. 當使用Socket.IO時,能夠進行雙向通訊,其中每一方——客戶端或服務器均可以發起請求。在AJAX中,只有客戶才能發起請求!

  6. Socket.IO有更多的傳輸選項,包括Adobe Flash。

如今,對於我本身的應用,我最感興趣的是發起請求並從(Node.js)服務器獲取數據的速度!

關於與CUBRID數據庫中間件的數據通訊,由於大約90%的數據訪問是隻讀的,一個好的數據緩存機制顯然是一個不錯的途徑!但關於這個,我下次再談。

因此我決定對他們的(Ajax和socket)速度進行測試,看看哪個更快(至少在個人硬件和軟件環境下)!個人硬件環境是:i5處理器,8GB內存和英特爾X25 SSD硬盤。

可是嚴格來講,任何性能測試都取決於您的硬件和軟件配置,在你本身的環境中去測試終歸是一個好主意,不要過於依賴你在互聯網上找到的各類信息,更多的問題須要你本身去發現!

我要作的測試須要知足如下要求:

  • 測試:

    • AJAX

    • Socket.IO 持續鏈接模式

    • Socket.IO 非持續連接模式

  • 測試客戶端與服務器之間進行十、100,、250、500條數據交換時的狀況

  • 中間件服務器(Node.js Web 服務器)和客戶端(瀏覽器)之間交換的每條數據都是一個4KBytes的隨機數據串

  • 在 release(非調試)模式下運行服務器

  • 用Firefox做爲客戶端

  • 最小化控制檯消息輸出,不論是服務器端仍是客戶端

  • 在客戶端頁面硬性從新加載後進行每一個測試

  • 每次測試至少重複3次,以確保結果一致

測試Socket.IO,使用持久鏈接

我建立了一小型的小Node.js服務器,用它處理客戶端請求:

io.sockets.on('connection', function (client) {
    client.on('send_me_data', function (idx) {
        client.emit('you_have_data', idx, random_string(4096));
    });
});

這是我用於測試的JS客戶端腳本:

var socket = io.connect(document.location.href);
 
socket.on('you_have_data', function (idx, data) {
    var end_time = new Date();
    total_time += end_time - start_time;
    logMsg(total_time + '(ms.) [' + idx + '] - Received ' + data.length + ' bytes.');
    if (idx++ < countMax) {
        setTimeout(function () {
            start_time = new Date();
            socket.emit('send_me_data', idx);
        }, 500);
    }
});

測試Socket.IO,使用非持久鏈接

此次,對於每次數據交換,我都打開一個新的socket-io鏈接。

Node.js服務器代碼與上一個相似,可是我決定在鏈接以後當即發送客戶端數據,由於每次數據交換都會啓動一個新的鏈接:

io.sockets.on('connection', function (client) {
    client.emit('you_have_data', random_string(4096));
});

客戶端測試代碼:

function exchange(idx) {
    var start_time = new Date();
    var socket = io.connect(document.location.href, {'force new connection' : true});
 
    socket.on('you_have_data', function (data) {
        var end_time = new Date();
        total_time += end_time - start_time;
        socket.removeAllListeners();
        socket.disconnect();
        logMsg(total_time + '(ms.) [' + idx + '] - Received ' + data.length + ' bytes.');
         
        if (idx++ < countMax) {
            setTimeout(function () {
                exchange(idx);
            }, 500);
        }
    });
}

測試AJAX

最後是AJAX測試...

Node.js服務器代碼與之前的代碼不一樣:

res.writeHead(200, {'Content-Type' : 'text/plain'});
res.end('_testcb(\'{"message": "' + random_string(4096) + '"}\')');

至於客戶端代碼,這是我之前測試的:

function exchange(idx) {
    var start_time = new Date();
 
    $.ajax({
        url : 'http://localhost:8080/',
        dataType : "jsonp",
        jsonpCallback : "_testcb",
        timeout : 300,
        success : function (data) {
            var end_time = new Date();
            total_time += end_time - start_time;
            logMsg(total_time + '(ms.) [' + idx + '] - Received ' + data.length + ' bytes.');
             
            if (idx++ < countMax) {
                setTimeout(function () {
                    exchange(idx);
                }, 500);
            }
        },
        error : function (jqXHR, textStatus, errorThrown) {
            alert('Error: ' + textStatus + " " + errorThrown);
        }
    });
}

記住,當將AJAX和Node.js一塊兒編碼時,你須要考慮到可能的跨域請求和同源策略,所以應該使用基於JSONP的格式!

順便說一句,能夠看到,我僅引用了測試代碼中最重要的部分,以節省篇幅。若是有人須要完整的服務器和客戶端代碼,請告訴我 - 我很樂意分享。

好的 - 如今看看完成這些工做後咱們獲得了什麼!

我分別運行了十、100、250和500個數據交換的測試,這是最終測試結果:

Data exchanges Socket.IO NON-persistent (ms.) AJAX (ms.) Socket.IO persistent (ms.)
10 90 40 32
100 900 320 340
250 2,400 800 830
500 4,900 1,500 1,600

看看結果,咱們會注意一些狀況:

  1. 對於每種類型的測試,結果遵循線性增加的規律,這很好——代表結果是一致的。

  2. 結果清楚地代表,當使用Socket.IO非持久性鏈接時,性能數字比其餘數據差得多。

  3. 在AJAX和Socket.IO持久鏈接之間彷佛並無太大區別——咱們只談幾毫秒的差別。 這意味着,若是您天天的數據交換次數不超過10,000次的話,用戶基本上不會注意到速度差別...

下圖描述了在測試中得到的數字:

那麼接下來呢?

嗯,我必須弄清楚本身須要支持什麼樣的流量,而後我將從新運行這些測試,但此次不包括Socket.IO非持久鏈接。由於很明顯,我須要在AJAX和持久的Socket.IO鏈接之間進行選擇。

並且我也瞭解到,最有可能的是,速度差別不會像人們想象的那樣大,至少不是爲了一個「小流量」的網站,因此我在肯定本身的解決方案時,還須要研究每一個方法/技術的其餘優缺點!

  1. 這裏有一些資源,能夠找到關於Node.js、Socket.IO 和 AJAX 的一些有趣的東西:

關注微信公衆號:充實的腦洞, 一個技術宅的保留地
相關文章
相關標籤/搜索