2012-10-12 64 views
6

編輯的Node.js +快遞隨機中斷請求,導致網關超時

多putzing身邊後,我終於找到的東西,好像它可能是一個固體鉛:

快遞庫在當前使用Node + OAuth模塊執行多個出站請求(例如,Facebook,Twitter等)時未能接受傳入請求。我可以通過在我的代碼中放置大量日誌來確定這一點,我發現在出站請求中間沒有觸發「開始 - 請求」日誌(如下所述)。

我已經能夠證明,當Node + OAuth模塊發出幾個出站請求時,通過瀏覽器窗口對我的API的入站請求將掛起並且不會被接收,直到其中一個出站OAuth請求已完成。

當然,我已經做了:

require('http').globalAgent.maxSockets = 999; 

每一個建議在IRC,我已經添加

console.log(require('http').globalAgent.requests); 

但這似乎總是=== {},這意味着沒有待處理的入站請求AFAIK。

因此我留下得出結論,無論是Node.js的或表達的是選擇到,出於某種原因,由於出站請求塊傳入的請求,即使應該有大量可用的套接字...

任何人有任何提示如何解決這個問題?


我在使用快遞,貓鼬等,部署在Amazon雲這奇妙的作品和快速的99%的時間node.js中創建的API。

除了,過一段時間,請求似乎不知何故掉落或忽略。我正在討論通常以毫秒爲單位完成的請求,並且沒有任何清晰的圖像,因此隨機無響應爲什麼

症狀是一個簡單的「網關超時」連接到API端點時。在同一個客戶端使用相同的參數創建一個相同的請求,就在之前或之後的某個時刻,可以很好地工作。

當然,我首先想到的是「咄,服務器超載!」所以我花了很多時間來優化我的請求,monogoDB等等。最後,我發現整個電路板(包括Node.js服務器和Mongo服務器)的CPU /磁盤/ RAM使用率爲非常低。我使用Scout和RightScale實時跟蹤我的服務器,並且記錄超過100ms的任何請求或查詢。我的節點服務器目前有5GB的可用內存,70%的可用CPU(第一核心)等等,所以我99.99%肯定這不是性能問題。

最後,我就拼命回落:我重視我的客戶(S)由隨機數所有請求。然後,在node.js應用程序中,當請求第一次被接收並且完成時,我做了一個console.log()。例如,這裏是我的快遞使用的中間件:

var configureAPI = function() { 
    return function(req, res, next) { 
     if(req.body.ruid) 
      console.log(req.body.ruid); 

     // more middleware stuff... 
    }; 
} 
server.configure(function(){ 

    server.use(express.bodyParser()); 
    server.use(configureAPI()); 
    server.use(onError); 

    // ... more config stuff 
} 

我找到了什麼讓我震驚:顯然,節點。js應用程序甚至沒有收到有問題的請求。我有一個JavaScript web應用程序,並打印與請求一起發送到控制檯的「ruid」。只要請求成功,node.js控制檯中就會顯示相應的「ruid」。每當它超時,就沒有。


編輯:更多調試&信息。

我的應用程序服務器實際上啓動(並繼續)也提供PHP(因此,他們已安裝Apache等)。我需要http://streamified.me來爲我的網站(PHP)和http://api.streamified.me服務我的API(node.js)...所以我有一行在我的httpd.conf文件中導致請求到api.streamified.me(而不是streamified.me )通過8888端口去的Node.js:

RewriteCond %{HTTP_HOST} ^api.streamified.me 
RewriteRule ^(.*) http://localhost:8888$1 [P] 

所以,在同一個httpd.conf文件,我打開RewriteLogLevel 5,然後創建一個簡單的PHP +捲曲腳本在我的本地打我的API。用隨機的URL(這會導致node.js觸發一個簡單的「not found」響應)streamified.me,直到它導致網關超時。在這裏,你可以看到它發生了 - 重寫日誌顯示請求已被應用程序服務器明確接收並轉發到端口8888 ...但它從來沒有被node.js收到(或者至少在中間件從來沒有得到它的第一行的第一行代碼...)

enter image description here


我已經一遍又一遍我的Node.js代碼,並敢肯定我沒有阻擋代碼,即使我這樣做了,我也無法想象它會阻塞線程足夠長的時間以致錯過某個請求,而不會在某處引發紅旗。

我錯過了什麼?傳入的套接字是否會被阻塞?我通過我的node.js應用程序向外部API發送了相當多的HTTP請求,但AFAIK不應該阻止傳入的套接字。


當然,我有錯誤記錄到位。我已經在過程級別上啓用它...

process.addListener("uncaughtException", function (err) { 
    // some logging code 
} 

和Express級別(上面的onError處理程序)。我知道我的錯誤日誌記錄功能是有效的,因爲我看過他們都在之前發作。但無論他們的報告圍繞着下降請求的時候什麼,我也不在控制檯中看到什麼...


  • 快遞版本:3.0.0rc5
  • Node.js的版本:0.8。在一個標準的亞馬遜雲設置(m1.large實例)運行的node.js應用程序,後面2個負載平衡器12分
  • 2的情況下,連接到3×副本集MongoDBs(也m1.large)
+0

您已確認負載均衡器正在接收請求並將其成功發送到節點服務器?當一個人失敗時你多久提出一次請求? – Bill

+0

相同的LB /應用程序服務器也提供PHP文件,永遠不會造成超時。但我不太清楚如何確認LB正確轉發到節點服務器,不過,除此之外。我沒有出現任何交通高峯。 Rightscale上的apache日誌報告一致~10 req/sec。 –

+0

我發現了一些列出的類似問題的錯誤,但它們都是由0.6.6修復的。您可能會嘗試升級到最新版本,因爲自0.6版以來已經進行了大量修復/改進。我還建議你在你的應用服務器上設置網絡嗅探器,以確保服務器實際上正在接收數據包。 – Bill

回答

1

這聽起來像你鎖起來您的Node線程太長,導致傳入連接在處理它們之前超時。節點是單線程的,所以它一次只能做一件事,它不能選擇阻止一個傳入的請求。它只能接受傳入的請求,因爲它忙於做其他事情。你需要弄清楚它在忙什麼。

如果你不發出出站請求,一切工作正常?如果是這樣,你需要看看這些請求的代碼,以確保你沒有等待迴應。

+0

這是有道理的。我是積極的,我沒有做任何「同步」任務,我使用Q來實現承諾。唯一值得關注的是JSON.parse()命令,它們正在評估大量(〜2MB)的數據字符串。這些操作可能會阻止該線程嗎? –

+0

有些數據可能會返回大於2MB? 2MB不應該掛起線程足夠長的時間來放棄請求(雖然它會阻塞一些東西),但如果偶爾嘗試解析更大的字符串,它可能是罪魁禍首。您可以嘗試用一個調用來替換解析,以返回靜態數據以查看是否可以解決問題。 – Bill

+0

嗯,我無法真正使用靜態數據,因爲JSON解析會影響下游的事情,並且通過使用靜態數據,我只能測試1場景......無論如何,我開始輸出解析()次,有時大約在100ms左右(並且通常有幾次背靠背,儘管按承諾分開)。另外,我剛剛發生了第一次出現OOM錯誤「致命錯誤:CALL_AND_RETRY_2分配失敗 - 進程內存不足」......這讓我想知道這是否是問題的一部分......雖然這是我第一次我見過這樣的錯誤... –