2013-06-22 57 views
13

該問題特別針對Nodejitsu,但類似的效果似乎在其他VPS上發生。我有一個使用socket.io的實時遊戲,並且我注意到的一件事是偶爾服務器會在響應之前等待過多的時間。如果在該時間段內發送了多個請求,則它們的行爲就好像它們已經全部排隊並一次處理。我懷疑它與共享硬件上其他用戶的存在有着模糊的關聯(就像任何VPS一樣)。NodeJS的高延遲

總之,測試了這一點(並確保它不是由於我的遊戲的代碼),我建立了一個最小的測試案例:

express = require('express') 
http = require('http') 

app = express() 
server = http.Server(app) 

io = require('socket.io').listen(server) 

io.sockets.on('connection', function(sock){ 
    sock.on('perf', function(data, cb){ 
     cb([Date.now()]); //respond with the current time 
    }) 
}) 

app.get('/', function(req, res){ 
    res.header("Access-Control-Allow-Origin", "*") 
    res.header("Access-Control-Allow-Methods", "HEAD,GET,PUT,POST,DELETE") 
    res.header("Access-Control-Allow-Headers", "X-Requested-With") 

    res.end(JSON.stringify([Date.now().toString()])); //http equivalent of perf function 
}) 

server.listen(process.env.PORT || 6655, function(){ 
    console.log('listening now') 
}) 

我做了一個簡單的空白HTML頁面插座。 io會定期發送一個perf事件和時間來回復觸發所花費的時間。和它仍然顯示同樣的事情:

graph showing lag spike

注意,酒吧長度表示的時間量,而不是線性數量的平方根。

當我不是依靠socket.io時,我使用XHR來做類似的當前響應時間測量,結果非常相似,很多低延遲響應(儘管基線比websockets更高,如預期的那樣)和一些似乎堆積起來的偶然尖峯。

奇怪的是,如果您在多個瀏覽器窗口和不同瀏覽器中打開它,似乎不同瀏覽器之間存在關聯(以及它在某些服務器上完全不存在或顯着較不頻繁的事實),這似乎暗示這是服務器端現象。但是,某些瀏覽器會出現延遲高峯,而其他瀏覽器則會出現延遲高峯,並且同一會話的兩個Chrome窗口看起來幾乎完全相同,這表明這是本地發生的事情(每臺計算機或每個瀏覽器,網絡明智的)。

從左至右:Chrome隱身,鉻(常規),火狐,Chrome(常規)

charts on four windows

無論如何,這已經困惑我幾個月,我真的想明白了什麼導致它,以及如何解決它。

+1

我很好奇,如果你可以直接在服務器上打開本地連接(也許有類似phantomjs的東西),並執行相同的測量,如果你會看到類似的尖峯或不。我也很好奇你使用的是什麼版本的瀏覽器,以及是否有閃回,長輪詢或iframes。看起來你正在運行沒有會話的快遞,所以它似乎不是會話相關的GC或類似的東西,你肯定服務器沒有重啓或任何事情(這可能會顯示在所有瀏覽器同一時間,所以可能不會,但只是問)。 – hoonto

+0

我猜你在這期間已經監視了服務器的統計數據?好奇的是,如果在同一時間有任何相關的尖峯或內存或CPU下降。如果您有權訪問數據中心,則可以在那裏插入本地交換機並消除大部分網絡干擾,但這可能不是一種選擇......如果他們從數據中提供了socket.io監控服務中央。 – hoonto

+1

實際上,你可以編寫一個本地的socket.io節點客戶端,並在同一臺服務器上本地運行它,並對其進行度量。對不起,垃圾郵件你太多了,性能問題可能就像乾草堆裏的針,所以只是試圖拋出我能想到的一切,這可能有助於將問題縮小到某個特定區域。 – hoonto

回答

0

我知道這可能聽起來很奇怪,但你認爲這不是節點的問題,但與操作系統設置。你有沒有檢查你的文件句柄和操作系統顯示給套接字的連接數量?你是否也確保操作系統中的套接字超時足夠低?我遇到了與其他代碼類似的聲音性能問題,它變成了操作系統而不是代碼。同時檢查包並查看它在套接字上的打開允許連接的功能。我沒有看過節點代碼,但遇到了與java中的http客戶端庫類似的問題。剛剛備份的應用程序只是連接數量的配置問題。

1

我假設你檢查了你是否有CPU或RAM問題。

能夠以「令人驚訝」的方式減慢節點的唯一一件事就是垃圾收集器 - 試着用--trace*來運行節點,看看發生了什麼。 (見node --v8-options。)

我個人認爲你沒有發現任何東西,因爲 - 這就是我的感覺 - 這個問題在別的地方。

由於500毫秒的乘法的完美延遲,我假設你有一個數據包丟失。你可以用ifconfig查看是否是一般性問題,然後是tcpdump這些數據包,看看它們是否重發。

+0

雖然我只用了一點節點,但我已經寫了一些Java服務器代碼。我們擔心延遲的主要原因之一是垃圾收集。許多基於虛擬機的語言(如Javascript/Node)的問題是延遲只能像虛擬機允許的那樣預測。在Java的情況下,我們通常會努力減少垃圾收集,而不是因爲延遲,而是因爲延遲尖峯。以防萬一,我肯定會看一下GC。 – sasbury

0

你看到這個的原因是因爲Nagle的算法。這是一種在I/O上使用的算法,可以緩存數據一段時間,然後發送更大的數據塊。它被用來保存你的傳輸(在套接字中)。你可以在這裏閱讀更多關於http://en.wikipedia.org/wiki/Nagle's_algorithm

要禁用Nagle的算法(當你想盡可能快地發送大量的小請求時很好),你可以做socket.setNoDelay(true);如果你使用net.Socket()。在socket.io的情況下,我相信Nagle默認已經禁用了Websockets,但不一定適用於其他協議。我會建議使用node.js的net.Sockets運行一個測試,禁用Nagle並查看你得到了什麼。

+3

Nagle只在每個連接的基礎上工作,並將小包連接成大包。這不是問題,因爲您爲每次通話建立了新的連接。當你有實時流媒體時,Nagle只能成爲一個問題。 – CFrei