随着流量的增加,Node.js出现EMFILE错误

73

我最近在运行Node.js的网站上接收到了很多流量。随着流量的增加,它开始经常崩溃,这之前还从未发生过。我在日志中看到了以下错误:

{ [Error: connect EMFILE] code: 'EMFILE', errno: 'EMFILE', syscall: 'connect' }
Error: connect EMFILE
    at errnoException (net.js:670:11)
    at connect (net.js:548:19)
    at net.js:607:9
    at Array.0 (dns.js:88:18)
    at EventEmitter._tickCallback (node.js:192:40)

有人知道为什么它会崩溃吗?还有解决方法吗?

我正在使用Express.js和Socket.io。它在Ubuntu上运行。


4
EMFILE错误表示操作系统拒绝您的程序打开更多的文件/套接字,请参考:https://dev59.com/Z3VD5IYBdhLWcg3wRpaX。 - stewe
感谢stewe!更改ulimit解决了这个问题。 - codekick
2
我认为,这个问答绝对值得比“Hello World”更多的关注。开发者可以随意打开并发套接字,而没有任何限制,但是他们不知道这意味着允许大量请求打开套接字,从而导致应用程序崩溃并搞乱所有事情的事实。即使这可能是一个严重的漏洞,没有人会警告。在学习如何使用forever之前,必须通知开发人员这一点。 - Константин Ван
为了防止您的应用程序因大量连接而崩溃,首先需要确定没有资源泄漏―即您的应用程序不会创建和保持不必要的连接;然后其次,可以选择进行以下操作之一:限制可用并发套接字,或者增加操作系统打开套接字的限制 - Константин Ван
3个回答

71

14
提高套接字限制并不能修复漏洞问题,它只能暂时延缓应用程序崩溃的时间。 - jpillora
@jpillora,你有什么建议来预防泄露吗?我也遇到了同样的问题,但我不想通过增加ulimit来解决它,因为像你所说的那样,这只是一个临时的解决方法。 - Rob
3
@Robert 有时候增加ulimit确实是解决方案,比如如果它设置为256且你的流量很高。但在我的情况下,我一直在重复打开文件流但从未关闭它们,我用lsof -p <nodes pid>发现了这个泄漏问题。如果这种方法失败,你可以使用izaacs的graceful-fs模块。 - jpillora
2
不幸的是,graceful-fs模块对我来说并没有解决问题。我达到了套接字的限制,而不是因为使用fs打开了太多文件,但还是感谢您的帮助。 - Rob
1
套接字和文件都是文件描述符,ulimit 修改文件描述符限制。 - jpillora
显示剩余3条评论

23

EMFILE意为最大文件错误,表示操作系统拒绝您的程序打开更多的文件描述符。

请注意,系统中打开的文件包括磁盘文件、命名管道、网络套接字和所有进程打开的设备。

您的操作系统指定每个进程的打开文件限制。

要检查系统中打开文件的限制,请使用ulimit -a命令。通常在类Unix系统上,默认值为1024。

如果限制是1024,则表示您/进程最多可以打开1024个文件。如果超过此限制,则openpipedup系统调用将失败并产生EMFILE错误。

当您遇到EMFILE时,这通常表示代码中存在泄漏。将ulimit增加到更高的值不是解决方案,因为程序中存在泄漏。

您应该尝试找出泄漏的原因。以下是在类Unix操作系统中用于调试的内容:

  1. lsof表示列举打开的文件命令,给出打开文件的列表。假设您的nodeJS程序存在泄漏,因此要查找程序打开的文件描述符总数:

    lsof | grep node | wc -l

  2. 要查找套接字的文件描述符,请使用:

    lsof -n -i -P | grep node

使用此方法,我们可以找出泄漏的位置,然后进行修正。


5

在我的情况下,我们已经将Mac上的ulimit设置和kern.maxfiles配置设置为最高值。

问题的解决方法是全局限制最大套接字数。在较新版本的Node中,该限制为Infinity。

尝试添加以下代码行:

var https = require('https');
var http = require('http');

https.globalAgent.maxSockets = 5;
http.globalAgent.maxSockets = 5;

在使用请求库时,您可以配置以下设置。
请参见:https://github.com/request/request#request---simplified-http-client 有关maxSockets的更多信息,请参见:https://nodejs.org/api/http.html#http_agent_maxsockets

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接