几天来,我一直在寻找一个有效的错误解决方案
错误:EMFILE,打开的文件太多
似乎很多人都有同样的问题。通常的答案是增加文件描述符的数量。所以,我试过了:
sysctl -w kern.maxfiles=20480
缺省值为10240。在我看来,这有点奇怪,因为我在目录中处理的文件数量低于10240。更奇怪的是,在增加了文件描述符的数量之后,我仍然收到相同的错误。
第二个问题:
经过多次搜索,我找到了一个解决“打开文件太多”问题的方法:
var requestBatches = {};
function batchingReadFile(filename, callback) {
// First check to see if there is already a batch
if (requestBatches.hasOwnProperty(filename)) {
requestBatches[filename].push(callback);
return;
}
// Otherwise start a new one and make a real request
var batch = requestBatches[filename] = [callback];
FS.readFile(filename, onRealRead);
// Flush out the batch on complete
function onRealRead() {
delete requestBatches[filename];
for (var i = 0, l = batch.length; i < l; i++) {
batch[i].apply(null, arguments);
}
}
}
function printFile(file){
console.log(file);
}
dir = "/Users/xaver/Downloads/xaver/xxx/xxx/"
var files = fs.readdirSync(dir);
for (i in files){
filename = dir + files[i];
console.log(filename);
batchingReadFile(filename, printFile);
不幸的是,我仍然收到相同的错误。
这段代码有什么问题?
当graceful-fs不起作用时……或者您只是想了解泄漏从哪里来。遵循这个过程。
(例如,如果你的问题是套接字,优雅-fs不会修复你的马车。)
摘自我的博客文章:http://www.blakerobertson.com/devlog/2014/1/11/how-to-determine-whats-causing-error-connect-emfile-nodejs.html
如何隔离
该命令将输出nodejs进程的打开句柄数:
lsof -i -n -P | grep nodejs
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
...
nodejs 12211 root 1012u IPv4 151317015 0t0 TCP 10.101.42.209:40371->54.236.3.170:80 (ESTABLISHED)
nodejs 12211 root 1013u IPv4 151279902 0t0 TCP 10.101.42.209:43656->54.236.3.172:80 (ESTABLISHED)
nodejs 12211 root 1014u IPv4 151317016 0t0 TCP 10.101.42.209:34450->54.236.3.168:80 (ESTABLISHED)
nodejs 12211 root 1015u IPv4 151289728 0t0 TCP 10.101.42.209:52691->54.236.3.173:80 (ESTABLISHED)
nodejs 12211 root 1016u IPv4 151305607 0t0 TCP 10.101.42.209:47707->54.236.3.172:80 (ESTABLISHED)
nodejs 12211 root 1017u IPv4 151289730 0t0 TCP 10.101.42.209:45423->54.236.3.171:80 (ESTABLISHED)
nodejs 12211 root 1018u IPv4 151289731 0t0 TCP 10.101.42.209:36090->54.236.3.170:80 (ESTABLISHED)
nodejs 12211 root 1019u IPv4 151314874 0t0 TCP 10.101.42.209:49176->54.236.3.172:80 (ESTABLISHED)
nodejs 12211 root 1020u IPv4 151289768 0t0 TCP 10.101.42.209:45427->54.236.3.171:80 (ESTABLISHED)
nodejs 12211 root 1021u IPv4 151289769 0t0 TCP 10.101.42.209:36094->54.236.3.170:80 (ESTABLISHED)
nodejs 12211 root 1022u IPv4 151279903 0t0 TCP 10.101.42.209:43836->54.236.3.171:80 (ESTABLISHED)
nodejs 12211 root 1023u IPv4 151281403 0t0 TCP 10.101.42.209:43930->54.236.3.172:80 (ESTABLISHED)
....
注意:1023u(最后一行)——这是第1024个文件句柄,它是默认的最大值。
现在,看看最后一列。指示打开的资源。您可能会看到许多行都具有相同的资源名称。希望现在可以告诉您在代码的哪里查找泄漏。
如果不知道多个节点进程,首先查找哪个进程的pid为12211。它会告诉你整个过程。
在我上面的例子中,我注意到有一堆非常相似的IP地址。他们都是54.236.3分。###通过做ip地址查找,能够确定在我的情况下,它是pubnub相关的。
命令参考
使用此语法确定一个进程有多少个打开句柄…
获取某个pid的打开文件数
我使用这个命令来测试在我的应用程序中执行各种事件后打开的文件数量。
lsof -i -n -P | grep "8465" | wc -l
# lsof -i -n -P | grep "nodejs.*8465" | wc -l
28
# lsof -i -n -P | grep "nodejs.*8465" | wc -l
31
# lsof -i -n -P | grep "nodejs.*8465" | wc -l
34
你的流程限制是什么?
ulimit -a
你想要的线条是这样的:
open files (-n) 1024
永久更改限制:
在Ubuntu 14.04, nodejs v. 7.9上测试
如果你希望打开很多连接(websockets就是一个很好的例子),你可以永久增加限制:
文件:/etc/pam.D /common-session(添加到结尾)
会话需要pam_limits.so
文件:/etc/security/limits.conf(添加到末尾,如果已经存在,则编辑)
根软nofile 40000
根硬nofile 100000
重新启动nodejs,从ssh注销/登录。
这可能不适用于旧的NodeJS,你需要重新启动服务器
如果您的节点使用不同的uid运行,则使用。
对于同一个问题,我做了上面提到的所有事情,但都不起作用。我试了下,它工作100%。简单的配置更改。
选项1:设置限制(大多数情况下都不起作用)
user@ubuntu:~$ ulimit -n 65535
检查电流限制
user@ubuntu:~$ ulimit -n
1024
选项2:将可用限制增加到例如65535
user@ubuntu:~$ sudo nano /etc/sysctl.conf
添加下面的行
fs.file-max = 65535
运行此命令以刷新新的配置
user@ubuntu:~$ sudo sysctl -p
编辑以下文件
user@ubuntu:~$ sudo vim /etc/security/limits.conf
向它添加以下行
root soft nproc 65535
root hard nproc 65535
root soft nofile 65535
root hard nofile 65535
编辑以下文件
user@ubuntu:~$ sudo vim /etc/pam.d/common-session
把这一行加进去
session required pam_limits.so
注销并登录并尝试以下命令
user@ubuntu:~$ ulimit -n
65535
选项3:只添加这一行
DefaultLimitNOFILE=65535
到 /etc/systemd/system.conf 和 /etc/systemd/user.conf
以下是我的观点:考虑到CSV文件只是几行文本,我已经流化了数据(字符串)以避免这个问题。
在我的用例中最简单的解决方案。
它可以与优雅fs或标准fs一起使用。请注意,在创建文件时,文件中不会有头文件。
// import graceful-fs or normal fs
const fs = require("graceful-fs"); // or use: const fs = require("fs")
// Create output file and set it up to receive streamed data
// Flag is to say "append" so that data can be recursively added to the same file
let fakeCSV = fs.createWriteStream("./output/document.csv", {
flags: "a",
});
和数据,需要流到文件我已经这样做了
// create custom streamer that can be invoked when needed
const customStreamer = (dataToWrite) => {
fakeCSV.write(dataToWrite + "\n");
};
注意,dataToWrite只是一个带有自定义分隔符“;”或“,”的字符串。
即。
const dataToWrite = "batman" + ";" + "superman"
customStreamer(dataToWrite);
这将向文件写入“batman;superman”。
请注意,在这个示例中没有错误捕获或其他任何东西。
文档:https://nodejs.org/api/fs.html # fs_fs_createwritestream_path_options