2013-06-26 33 views
0

我正在做一些負載測試和編寫節點腳本來做到這一點。我的結果非常差,直到我意識到我的測試代碼纔是怪罪。我每秒平均約30-50個請求(進入服務器)使用下面的代碼來提出請求。 30-50似乎非常低。這是在一個4核心的Mac上。這是對的還是我做了一件完全錯誤的事情?http.request()每秒每個node.js進程

var http = require('http'); 
var sys = require('util'); 

http.globalAgent.maxSockets = 100000; 

var http = require('http'); 
http.globalAgent.maxSockets = 100000; 

var Request = function (request, params, host, port, completionFn, errorFn) 
{ 
    if(!params) 
    params = ''; 

    if(typeof(errorFn) != 'function') 
    { 
    errorFn = function (e) 
     { 
      console.log('request error!? ' + e.message); 
      process.exit(); 
     } 
    } 

    var paramsStr = ''; 
    for(var item in params) 
    paramsStr += '&' + item + '=' + encodeURI(params[item]); 

    var path = '/' + request; 
    if(paramsStr != '') 
    path += '?' + paramsStr.substr(1); 

    var options = 
    { 
    host:  host, 
    port:  port, 
    path:  path, 
    agent: false 
    }; 

    http.request(options, 

    function (response) 
    { 
     var responseData = ''; 

     response.on('data', 

     function (chunk) 
     { 
      responseData += chunk; 
     } 

    ).on('end', 

     function() 
     { 
      completionFn(httpRequest.To_JSON(responseData)); 
     } 

    ).on('error', errorFn); 
    } 

).on('error', errorFn).end(); 
}; 

新信息:

有趣的是在Chrome中運行這個網我大約每秒250請求這似乎單個節點更合理。儘管瀏覽器確實很快崩潰。

for(var i = 0; i < 1000000; i++) 
{ 
    $.get('/service', {index:i},function(result){}).error(

    function() 
    { 
     out.append('fail '); 
    } 
); 
} 
+0

你有什麼代碼啓動這些請求?編寫基準測試的節點並不是一種特別好的語言。儘管您嘗試異步地發出請求,但內部事件可能非常同步。請教我的例子。 – ChrisCM

回答

0
/*jshint node:true */ 
var http = require('http'); 

var i = 100; 

var called = 0; 

while (i--) { 
    requestGoogle(); 
} 

function requestGoogle() { 
    'use strict'; 
    var requestNum = called++; 

    console.log('CALLED: ' + called); 
    var options = { 
     hostname: 'www.google.com', 
     port: 80, 
     path: '/', 
     method: 'GET' 
    }; 

    var req = http.request(options, function (res) { 
     res.setEncoding('utf8'); 
     res.on('data', function() { 
      console.log('RECIEVING DATA ON: ' + requestNum); 
     }); 

     res.on('end', function() { 
      console.log('CALLED: ' + --called); 
     }); 
    }); 

    req.on('error', function (e) { 
     console.log('problem with request: ' + e.message); 
    }); 

    req.end(); 
} 

所以,當我運行這個例子中,我注意到兩件事情。首先是在一開始我得到的數據來對各種請求的一個很好的組合:

RECIEVING方面的數據:2 RECIEVING方面的數據:0 RECIEVING方面的數據:2 RECIEVING方面的數據:0 RECIEVING DATA ON:3 RECIEVING DATA ON:3 RECIEVING DATA ON:3 RECIEVING DATA ON:3 RECIEVING DATA ON:3 RECIEVING DATA ON:3 RECIEVING DATA ON:3 RECIEVING DATA ON:1 RECIEVING DATA ON :1 獲取數據:1 獲取數據:1 RECIEVING方面的數據:1 RECIEVING方面的數據:1 RECIEVING方面的數據:1 RECIEVING方面的數據:1 RECIEVING方面的數據:4 RECIEVING方面的數據:4 RECIEVING方面的數據:4個

我們看到大塊從請求1,4,3,0,2 ...全部同時進入...真棒!那麼過了一段時間後,這種行爲會提煉出什麼樣的結果是一組非線性的結果,根本就不會發生混合。最終我們將事件循環與排隊請求分開。當我們做這個邏輯服務器端時,並不是立即循環函數調用,而是立即將請求排隊。無論有多少請求進入服務器(DDOS條件除外),節點進程調用它的事件處理程序都有很少的週期,並返回到主事件循環。

當你做一個客戶端,而循環,產卵請求,這些寶貴的幾個週期不可用。 INstead,我們擁有一個擁擠的事件循環,最終導致對請求的基本線性處理,並且一旦初始的10-13個請求已經接收到數據,它們就開始按順序接收它,事情發生的速度比您預期的要慢得多,相比節點能夠以多快的速度處理服務器端請求,因爲我們擁有一個擁擠的事件循環。您的客戶端程序本質上已經過DOSS自己! :)。

您可以嘗試通過增加套接字的數量來抑制這種行爲,但最終機器將會耗盡文件描述符。此時,節點會在涉及的調用中崩潰/調用錯誤處理程序,或者放慢速度並等待文件描述符變爲可用,從而以非常線性的同步方式處理未來的請求。有許多方法可以增加文件描述符,但最終要做好基準測試,則需要多臺計算機。沒有操作系統被設計爲處理足夠的套接字描述符/網絡I/O,即使是單節點服務器也能夠充分壓力測試。如果是這種情況,那麼DDOS攻擊會更容易!

另外:看看JMeter,壓力測試的客戶端比節點更好。

+0

是的,我沒有想到單個CPU的基準級吞吐量,只是比我得到的更多。我希望在服務器場上運行測試代碼以進行真正的測試。 – user1854983

+0

看看JMeter,這對於這種事情非常有用!如果你真的想要使用節點,嘗試使用set interval,但設置一個非常小的時間間隔,而不是立即啓動一堆請求。 http://jmeter.apache.org/ – ChrisCM

+0

雖然你是正確的,但是50很低,我的機器在啓動前獲得了400個請求。如果您在unix環境中,請嘗試使用ulimit更改文件描述符。 – ChrisCM