拿什么守护你的Node.JS进程: Node出错崩溃了怎么办?

被吐嘈的NodeJS的异常处理

许多人都有这样一种映像,NodeJS比较快; 但是因为其是单线程,所以它不稳定,有点不安全,不适合处理复杂业务; 它比较适合对并发要求比较高,而且简单的业务场景。

在Express的作者的TJ Holowaychuk的告别Node.js一文中列举了以下罪状:

Farewell NodeJS (TJ Holowaychuk)

?   you may get duplicate callbacks
?   you may not get a callback at all (lost in limbo)
?   you may get out-of-band errors
?   emitters may get multiple “error” events
?   missing “error” events sends everything to hell
?   often unsure what requires “error” handlers
?   “error” handlers are very verbose
?   callbacks suck

其实这几条主要吐嘈了两点: node.js错误处理很扯蛋,node.js的回调也很扯蛋。

事实上呢?

事实上NodeJS里程确实有“脆弱”的一面,单线程的某处产生了“未处理的”异常确实会导致整个Node.JS的崩溃退出,来看个例子, 这里有一个node-error.js的文件:

var http = require(‘http‘);

var server = http.createServer(function (req, res) {

//这里有个错误,params 是 undefined  var ok = req.params.ok;

res.writeHead(200, {‘Content-Type‘: ‘text/plain‘});  res.end(‘Hello World\n‘);});

server.listen(8080, ‘127.0.0.1‘);

console.log(‘Server running at http://127.0.0.1:8080/‘);

启动服务,并在地址栏测试一下发现 http://127.0.0.1:8080/  不出所料,node崩溃了

$ node node-errorServer running at http://127.0.0.1:8080/

c:\github\script\node-error.js:5  var ok = req.params.ok;                     ^TypeError: Cannot read property ‘ok‘ of undefined    at Server.<anonymous> (c:\github\script\node-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)

怎么解决呢?

其实Node.JS发展到今天,如果连这个问题都解决不了,那估计早就没人用了。

使用uncaughtException

我们可以uncaughtException来全局捕获未捕获的Error,同时你还可以将此函数的调用栈打印出来,捕获之后可以有效防止node进程退出,如:

process.on(‘uncaughtException‘, function (err) {  //打印出错误  console.log(err);  //打印出错误的调用栈方便调试  console.log(err.stack);});

这相当于在node进程内部进行守护, 但这种方法很多人都是不提倡的,说明你还不能完全掌控Node.JS的异常。

使用 try/catch

我们还可以在回调前加try/catch,同样确保线程的安全。

var http = require(‘http‘);

http.createServer(function(req, res) {  try {    handler(req, res);  } catch(e) {    console.log(‘\r\n‘, e, ‘\r\n‘, e.stack);    try {      res.end(e.stack);    } catch(e) { }  }}).listen(8080, ‘127.0.0.1‘);

console.log(‘Server running at http://127.0.0.1:8080/‘);

var handler = function (req, res) {  //Error Popuped  var name = req.params.name;

res.writeHead(200, {‘Content-Type‘: ‘text/plain‘});  res.end(‘Hello ‘ + name);};

这种方案的好处是,可以将错误和调用栈直接输出到当前发生的网页上。

集成到框架中

标准的HTTP响应处理会经历一系列的Middleware(HttpModule),最终到达Handler,如下图所示:

这些Middleware和Handler在NodeJS中都有一个特点,他们都是回调函数,而回调函数中是唯一会让Node在运行时崩溃的地方。根据这个特点,我们只需要在框架中集成一处try/catch就可以相对完美地解决异常问题,而且不会影响其它用户的请求request。

事实上现在的NodeJS WEB框架几乎都是这么做的,如OurJS开源博客所基于的WebSvr

就有这么一处异常处理代码:

Line: 207

  try {    handler(req, res);  } catch(err) {    var errorMsg      = ‘\n‘      + ‘Error ‘ + new Date().toISOString() + ‘ ‘ + req.url      + ‘\n‘      + err.stack || err.message || ‘unknow error‘      + ‘\n‘      ;

    console.error(errorMsg);    Settings.showError      ? res.end(‘<pre>‘ + errorMsg + ‘</pre>‘)      : res.end();  }

那么不在回调中产生的错误怎么办?不必担心,其实这样的node程序根本就起不起来。

此外node自带的 cluster 也有一定的容错能力,它跟nginx的worker很类似,但消耗资源(内存)略大,编程也不是很方便,OurJS并没有采用此种设计,未来如果流量达到一定程度,单个进程无法满足要求时,或采用多个服务器(VMs),起多个相互独立的node websvr进程,将需要共享的session存放在一处统一的redis数据库中。

守护NodeJS进程和记录错误日志

现在已经基本上解决了Node.JS因异常而崩溃的问题,不过任何平台都不是100%可靠的,还有一些错误是从Node底层抛出的,有些异常try/catch和uncaughtException都无法捕获。之前在运行ourjs的时侯,会偶尔碰到底层抛出的文件流读取异常,这就是一个底层libuv的BUG,node.js在0.10.21中进行了修复。

面对这种情况,我们就应该为nodejs应用添加守护进程,让NodeJS遭遇异常崩溃以后能马上复活。

另外,还应该把这些产生的异常记录到日志中,并让异常永远不再发生。

使用node来守护node

node-forever 提供了守护的功能和LOG日志记录功能。

安装非常容易

[sudo] npm install forever

使用也很简单

$ forever start simple-server.js$ forever list  [0] simple-server.js [ 24597, 24596 ]

还可以看日志

forever -o out.log -e err.log my-script.js

使用shell启动脚本守护node

使用node来守护的话资源开销可能会有点大,而且也会略显复杂,OurJS直接在开机启动脚本来进程线程守护。

如在debian中放置的 ourjs 开机启动文件: /etc/init.d/ourjs

这个文件非常简单,只有启动的选项,守护的核心功能是由一个无限循环 while true; 来实现的,为了防止过于密集的错误阻塞进程,每次错误后间隔1秒重启服务

WEB_DIR=‘/var/www/ourjs‘WEB_APP=‘svr/ourjs.js‘

#location of node you want to useNODE_EXE=/root/local/bin/node

while true; do    {        $NODE_EXE $WEB_DIR/$WEB_APP config.magazine.js        echo "Stopped unexpected, restarting \r\n\r\n"    } 2>> $WEB_DIR/error.log    sleep 1done

错误日志记录也非常简单,直接将此进程控制台当中的错误输出到error.log文件即可: 2>> $WEB_DIR/error.log  这一行, 2 代表 Error。

时间: 2024-10-25 18:13:49

拿什么守护你的Node.JS进程: Node出错崩溃了怎么办?的相关文章

拿什么守护你的Node.JS进程: Node出错崩溃了怎么办? foreverjs, 文摘随笔

守护进程 方案一 npm install forever https://github.com/foreverjs/forever 方案二 npm install -g supervisor http://www.cnblogs.com/pigtail/archive/2013/01/08/2851056.html 被吐嘈的NodeJS的异常处理 许多人都有这样一种映像,NodeJS比较快: 但是因为其是单线程,所以它不稳定,有点不安全,不适合处理复杂业务: 它比较适合对并发要求比较高,而且简单

Node.js进程管理之Process模块

在前面Node.js事件运行机制也有提到,Node.js应用在单个线程运行,但是现在大部分服务器都是多处理器,为了方便使用多个进程,Node.js提供了3个模块.Process模块提供了访问正在运行的进程.child_process模块可以创建子进程,并与他们通信.cluster模块提供了实现共享相同端口的集群服务能力,允许多个请求同时处理. 一.Process模块是一个无须使用require()就可以从node.js应用程序进行访问的全局对象. 二.进程I/O管道 Process为进程stdi

.NET程序员也学Node.js——初识Node.js

清明在石门休了八天假,一眨眼,4月又到中旬了...看到.NET在天朝彻底沦陷而又无能为力,我开始尝试去学习一些新的东西来充实自己,我自然是打死不会去学java的,没有为什么,于是乎,最近开始学习一些前端的开发技术,就让学习笔记来记录一下我的学习历程并同大家一起分享吧! 申明:我只是业余学着好玩的,顺便扩展一下视野,各位广大.NET同行不要被我带沟里去了,当然如果你想从事移动前端或者全栈开发的话还是有必要学习一下的. Node.js简介 Node.js 的推出,不仅从工程化的角度自动化掉更多琐碎费

Node.js进程通信模块child_process

前言 Node.js是一种单线程的编程模型,对Node.js的赞美和诟病的也都是因为它的单线程模型,所有的任务都在一个线程中完成(I/O等例外).单线程模型,不仅让代码非常简洁,更是直接避免了线程调度的复杂性:同样也是因为单线程,让CPU密集型计算应用,完全不适用. 在Node.js的内核中,给了我们一种新的选择,通过child_process模块创建新进程,从而实现多核并行计算. 目录 child_process介绍 child_process的基本使用:spawn, exec, execFi

Node.js进程管理器PM2浅析

作者:zhanhailiang 日期:2014-11-02 PM2是Node.js应用程序的进程管理管理,目前已在生产环境被普遍使用,提供以下特性: Transitional state of apps Process listing Automatic restart process based on memory Monitoring CPU/Memory usage Logs management Clustering Watch & Restart Reloading without d

windows下node.js进程间传递客户端socket的一些规律

最近在update我的一个github项目的时候,想要把原来单一进程的模式改成多进程的模式. 事情是这样的,我做了一个HTTP服务器,支持动态脚本. 在完成了一大堆各种各样的特性后,遇到了一个脚本超时的问题. 在我的HTTP服务器中,将页面分成了Template和Activity两个部分,一个是用做VIEW的,一个是用作MODULE的,也就是类似于ASP啦. 但是,由于NODE.js是单进程的,所以我无法控制Activity中的代码(为用户脚本). 所以,如果Activity中出现死循环,那么整

Node.js 进程平滑离场剖析

本文由云+社区发表 作者:草小灰 使用 Node.js 搭建 HTTP Server 已是司空见惯的事.在生产环境中,Node 进程平滑重启直接关系到服务的可靠性,它的重要性不容我们忽视.既然是平滑重启,就涉及到新旧进程的接替过渡: 首先,保证新进程平滑入场 其次,保证旧进程平滑离场 本文主要谈论下,在新旧进程接替过渡期间,如何保证旧进程平滑离场.那怎样的离场才算平滑的呢? 如何定义平滑离场 以进程离场作为时间分割点,我们可以把请求分为两类:增量请求和存量请求. 在进程离场前,停止接收新的(增量

关于安装完Node.js 出现node is not dedined 问题

今天想来接触下Node.js 神奇  怀着揣揣的心 从官网下载了windows 的64位mis版本  几个下一步就顺利安装完毕了 接着跟着新手教程走  不懂教程里的 苹果shell 是什么 反正就是检测下node的安装么  输入node -v 那么问题就来了: 什么情况: 跟想象的不一样 各种node  node -v  node -version  都是这么个情况...无语 再一看 这界面 cmd也有  然后打开windows的cmd  ...果然.... 原来是这么个情况...

自学Node.js: WebStorm+Node.js开发环境的配置

WebStorm是作为JS开发IDE存在的,并且支持流行的Node.js以及JQuery等js框架.而Node.js简单说就是一个JS类库并且配备有Google的V8 js引擎来解析和执行js脚本. 那WebStorm+Node.js这样一个组合,用来开发基于Node.js平台的应用是最方便不过的了,并且可以知道WebStorm这个IDE环境对js的支持是灰常强大的,有智能提示.断点调试.查看源码等等功能. 类似其他开发环境的搭建,下面简要说一下如何搭建一个开发环境并完成一个Demo实例. 1.