【发布时间】:2011-08-25 08:33:30
【问题描述】:
根据我的经验,php 服务器会向日志或服务器端抛出异常,但 node.js 只是简单地崩溃。用 try-catch 包围我的代码也不起作用,因为一切都是异步完成的。我想知道其他人在他们的生产服务器上做什么。
【问题讨论】:
标签: node.js crash try-catch production-environment
根据我的经验,php 服务器会向日志或服务器端抛出异常,但 node.js 只是简单地崩溃。用 try-catch 包围我的代码也不起作用,因为一切都是异步完成的。我想知道其他人在他们的生产服务器上做什么。
【问题讨论】:
标签: node.js crash try-catch production-environment
PM2
首先,我强烈建议为Node.js 安装PM2。 PM2 非常擅长处理崩溃和监控 Node 应用程序以及负载平衡。每当它崩溃、因任何原因停止甚至服务器重新启动时,PM2 都会立即启动 Node 应用程序。因此,如果有一天即使在管理我们的代码之后,应用程序崩溃了,PM2 也可以立即重新启动它。欲了解更多信息,Installing and Running PM2
其他答案真的很疯狂,您可以在 Node 自己的文档中阅读 http://nodejs.org/docs/latest/api/process.html#process_event_uncaughtexception
如果有人使用其他声明的答案,请阅读 Node Docs:
请注意,
uncaughtException是一种非常粗糙的异常处理机制,将来可能会被删除
现在回到我们防止应用本身崩溃的解决方案。
所以在经历了之后,我终于想出了 Node 文档本身的建议:
不要使用
uncaughtException,而是使用domains和cluster。如果您确实使用了uncaughtException,请在每次未处理的异常后重新启动您的应用程序!
DOMAIN 和 集群
我们实际上做的是向触发错误的请求发送错误响应,同时让其他人在正常时间完成,并停止在该工作人员中侦听新请求。
通过这种方式,域使用与集群模块齐头并进,因为当工作人员遇到错误时,主进程可以派生一个新工作人员。请参阅下面的代码以了解我的意思
通过使用Domain,以及使用Cluster 将我们的程序分成多个工作进程的弹性,我们可以做出更适当的反应,并以更高的安全性处理错误。
var cluster = require('cluster');
var PORT = +process.env.PORT || 1337;
if(cluster.isMaster)
{
cluster.fork();
cluster.fork();
cluster.on('disconnect', function(worker)
{
console.error('disconnect!');
cluster.fork();
});
}
else
{
var domain = require('domain');
var server = require('http').createServer(function(req, res)
{
var d = domain.create();
d.on('error', function(er)
{
//something unexpected occurred
console.error('error', er.stack);
try
{
//make sure we close down within 30 seconds
var killtimer = setTimeout(function()
{
process.exit(1);
}, 30000);
// But don't keep the process open just for that!
killtimer.unref();
//stop taking new requests.
server.close();
//Let the master know we're dead. This will trigger a
//'disconnect' in the cluster master, and then it will fork
//a new worker.
cluster.worker.disconnect();
//send an error to the request that triggered the problem
res.statusCode = 500;
res.setHeader('content-type', 'text/plain');
res.end('Oops, there was a problem!\n');
}
catch (er2)
{
//oh well, not much we can do at this point.
console.error('Error sending 500!', er2.stack);
}
});
//Because req and res were created before this domain existed,
//we need to explicitly add them.
d.add(req);
d.add(res);
//Now run the handler function in the domain.
d.run(function()
{
//You'd put your fancy application logic here.
handleRequest(req, res);
});
});
server.listen(PORT);
}
虽然Domain 正在等待弃用,并且将被删除,因为新的替代品如 Node 文档中所述
此模块正在等待弃用。一旦替代 API 完成,该模块将被完全弃用。绝对必须拥有域提供的功能的用户可能暂时依赖它,但预计将来必须迁移到不同的解决方案。
但是在没有引入新的替代品之前,Domain with Cluster 是 Node Documentation 建议的唯一好的解决方案。
为了深入了解Domain和Cluster阅读
https://nodejs.org/api/domain.html#domain_domain(Stability: 0 - Deprecated)
https://nodejs.org/api/cluster.html
感谢@Stanley Luo 为我们分享了关于集群和域的精彩深入解释
【讨论】:
restart your application after every unhandled exception! 如果 2000 个用户正在使用节点 Web 服务器来流式传输视频,并且 1 个用户出现异常,那么重新启动不会中断所有其他用户?
uncaughtException 并使用Domain 和Cluster 是不好的,如果一个用户遇到异常,那么只有他的线程从集群中删除并为他创建一个新的。而且您也不需要重新启动 Node 服务器。另一方面,如果您确实使用uncaughtException,则每次您的任何用户遇到问题时都必须重新启动服务器。因此,将域与集群一起使用。
domain 被完全弃用和删除时我们应该怎么做?
cluster和workers概念的人:sitepoint.com/…
我把这段代码放在我的 require 语句和全局声明下:
process.on('uncaughtException', function (err) {
console.error(err);
console.log("Node NOT Exiting...");
});
为我工作。我唯一不喜欢的是,如果我让事情崩溃,我不会得到尽可能多的信息。
【讨论】:
forever 或其他东西重新启动服务器更好。
正如提到的here,您会发现error.stack 提供了更完整的错误消息,例如导致错误的行号:
process.on('uncaughtException', function (error) {
console.log(error.stack);
});
【讨论】:
npm install supervisor
supervisor app.js
或者您可以安装forever。
所有这一切都会在您的服务器崩溃时通过重新启动来恢复它。
forever 可在代码中用于正常恢复任何崩溃的进程。
forever 文档有关于以编程方式处理退出/错误的可靠信息。
【讨论】:
使用 try-catch 可能会解决未捕获的错误,但在一些复杂的情况下,它并不能正确完成诸如捕获异步函数之类的工作。请记住,在 Node 中,任何异步函数调用都可能包含潜在的应用程序崩溃操作。
使用uncaughtException 是一种解决方法,但它被认为效率低下,并且很可能在未来的 Node 版本中被删除,所以不要指望它。
理想的解决方案是使用域:http://nodejs.org/api/domain.html
要确保您的应用在服务器崩溃时也能正常运行,请使用以下步骤:
使用节点集群为每个核心派生多个进程。因此,如果一个进程死亡,另一个进程将自动启动。查看:http://nodejs.org/api/cluster.html
使用域来捕获异步操作,而不是使用 try-catch 或未捕获。我并不是说 try-catch 或 uncaught 是不好的想法!
使用 forever/supervisor 来监控您的服务
添加守护程序以运行您的节点应用程序:http://upstart.ubuntu.com
希望这会有所帮助!
【讨论】:
试试 pm2 节点模块,它非常一致并且有很好的文档。具有内置负载均衡器的 Node.js 应用程序的生产流程管理器。请避免出现 uncaughtException 这个问题。 https://github.com/Unitech/pm2
【讨论】:
在 restify 上效果很好:
server.on('uncaughtException', function (req, res, route, err) {
log.info('******* Begin Error *******\n%s\n*******\n%s\n******* End Error *******', route, err.stack);
if (!res.headersSent) {
return res.send(500, {ok: false});
}
res.write('\n');
res.end();
});
【讨论】:
UncaughtException 是“一种非常粗糙的机制”(确实如此),现在不推荐使用域。但是,我们仍然需要一些机制来捕获(逻辑)域周围的错误。图书馆:
https://github.com/vacuumlabs/yacol
可以帮助您做到这一点。通过一些额外的编写,你可以在你的代码周围拥有很好的领域语义!
【讨论】:
默认情况下,Node.js 通过将堆栈跟踪打印到 stderr 并以代码 1 退出来处理此类异常,覆盖之前设置的任何 process.exitCode。
process.on('uncaughtException', (err, origin) => {
console.log(err);
});
【讨论】: