這篇文章要跟大家介紹如何解決NodeJS服務總是崩潰。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

許多人都有這樣一種映像,NodeJS比較快; 但是因為其是單線程,所以它不穩定,有點不安全,不適合處理複雜業務;它比較適合對並發要求比較高,而且簡單的業務場景。
事實上NodeJS里程確實有「脆弱」的一面,單線程的某處產生了「未處理的」異常確實會導致整個Node.JS的崩潰退出,來看個例子, 這裡有一個node-error.js的檔案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var http = require ('http');
var server = http.createServer( function (req, res) {
var ok = req.params.ok;
res.writeHead(200, {'Content-Type': 'text/plain'});
res. end ('Hello World
');
});
server.listen(8080, '127.0.0.1');
console.log('Server running at http:
|
登入後複製
啟動服務,並在網址列測試發現 http://127.0.0.1:8080/ 不出所料,node崩潰了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $ node node-error
Server running at http:
c:githubscript
ode-error.js:5
var ok = req.params.ok;
^
TypeError: Cannot read property 'ok' of undefined
at Server.<anonymous> (c:githubscript
ode-error.js:5:22)
at Server.EventEmitter.emit (events.js:98:17)
at HTTPParser.parser.onIncoming (http.js:2108:12)
at HTTPParser.parserOnHeadersComplete [ as onHeadersComplete] (http.js:121:23)
at Socket.socket.ondata (http.js:1966:22)
at TCP.onread (net.js:525:27)
|
登入後複製
怎麼#
1 2 3 4 5 6 | process.on('uncaughtException', function (err) {
console.log(err);
console.log(err.stack);
});
|
登入後複製
怎麼解決呢?
其實Node.JS發展到今天,如果連這個問題都解決不了,那估計早就沒人用了。
使用uncaughtException
我們可以uncaughtException來全域捕獲未捕獲的Error,同時你也可以將此函數的呼叫堆疊列印出來,捕獲之後可以有效防止node進程退出,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | var http = require ('http');
http.createServer( function (req, res) {
try {
handler(req, res);
} catch (e) {
console.log('
', e, '
', e.stack);
try {
res. end (e.stack);
} catch (e) { }
}
}).listen(8080, '127.0.0.1');
console.log('Server running at http:
var handler = function (req, res) {
var name = req.params.name;
res.writeHead(200, {'Content-Type': 'text/plain'});
res. end ('Hello ' + name);
};
|
登入後複製
這相當於在node進程內部進行守護, 但這種方法很多人都是不提倡的,表示你還不能完全掌控Node.JS的異常。
使用 try/catch
我們也可以在回呼前加上try/catch,同樣確保執行緒的安全性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | Line: 207
try {
handler(req, res);
} catch (err) {
var errorMsg
= '
'
+ 'Error ' + new Date ().toISOString() + ' ' + req.url
+ '
'
+ err.stack || err.message || 'unknow error'
+ '
'
;
console.error(errorMsg);
Settings.showError
? res. end ('<pre class = "brush:php;toolbar:false" >' + errorMsg + '
|
登入後複製
')
: res.end();
}
這個方案的好處是,可以將錯誤和呼叫堆疊直接輸出到目前發生的網頁上。
整合到框架中
標準的HTTP回應處理會經歷一系列的Middleware(HttpModule),最後到達Handler,如下圖:

#
這些Middleware和Handler在NodeJS中都有一個特點,他們都是回呼函數,而回呼函數中是唯一會讓Node在執行時崩潰的地方。根據這個 特點,我們只需要在框架中整合一處try/catch就可以相對完美地解決異常問題,而且不會影響其它使用者的請求request。
事實上現在的NodeJS WEB框架幾乎都是這麼做的,如 OurJS開源部落格所基於的 WebSvr
就有這麼一處例外處理程式碼:
1 | [sudo] npm install forever
|
登入後複製
那麼不在回呼中產生的錯誤怎麼辦?不必擔心,其實這樣的node程式根本就起不起來。
此外node自備的 cluster 也有一定的容錯能力,它跟nginx的worker很類似,但消耗資源(記憶體)略大,程式設計也不是很方便,OurJS並沒有採用此設計。
守護NodeJS進程和記錄錯誤日誌
現在基本上已經解決了Node.JS因異常而崩潰的問題,不過任何平台都不是100%可靠的,還有一些錯誤是從Node底層拋出的,有些異常try/catch和uncaughtException都無法捕捉。之前在運行ourjs的時侯,會偶爾碰到底層拋出的檔案流讀取異常,這就是一個底層 libuv的BUG,node.js在0.10.21中進行了修復。
面對這種情況,我們就應該為nodejs應用程式加入守護進程,讓NodeJS遭遇異常崩潰以後能馬上復活。
另外,也應該把這些產生的異常記錄到日誌中,並讓異常永遠不再發生。
使用node來守護node
node-forever 提供了守護的功能和LOG日誌記錄功能。
安裝非常容易
1 2 3 | $ forever start simple-server.js
$ forever list
[0] simple-server.js [ 24597, 24596 ]
|
登入後複製
使用也很簡單
1 | forever -o out.log -e err.log my-script.js
|
登入後複製
還可以看日誌
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | WEB_DIR='/ var /www/ourjs'
WEB_APP='svr/ourjs.js'
#location of node you want to use
NODE_EXE=/root/local/bin/node
while true; do
{
$NODE_EXE $WEB_DIR / $WEB_APP config.magazine.js
echo "Stopped unexpected, restarting
"
} 2>> $WEB_DIR /error.log
sleep 1
done
|
登入後複製
使用shell啟動腳本守護node
使用node來守護的話資源開銷可能會有點大,而且也會略顯複雜,OurJS直接在開機啟動腳本來進程執行緒守護。
如在debian中放置的ourjs 開機啟動檔: /etc/init.d/ourjs
這個檔案非常簡單,只有啟動的選項,守護的核心功能是由一個無限循環while true; 來實現的,為了防止過於密集的錯誤阻塞進程,每次錯誤後間隔1秒重啟服務
rrreee
錯誤日誌記錄也非常簡單,直接將此進程控制台當中的錯誤輸出到error.log檔案即可: 2>> $WEB_DIR/error.log 這一行, 2 代表Error。
推薦學習:javascript影片教學
####
以上是如何解決NodeJS服務總是崩潰的詳細內容。更多資訊請關注PHP中文網其他相關文章!