노드 및 오류 : EMFILE, 너무 많은 열린 파일
며칠 동안 나는 오류에 대한 해결책을 찾았습니다.
Error: EMFILE, too many open files
많은 사람들이 같은 문제가있는 것 같습니다. 일반적인 대답은 파일 디스크립터 수를 늘리는 것입니다. 그래서 나는 이것을 시도했다.
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);
불행히도 여전히 같은 오류가 발생합니다. 이 코드에 어떤 문제가 있습니까?
마지막 질문 (자바 스크립트 및 노드에 익숙하지 않음), 나는 약 5000 명의 일일 사용자에 대한 많은 요청으로 웹 응용 프로그램을 개발하는 과정에 있습니다. 파이썬과 자바와 같은 다른 언어로 프로그래밍하는 데 수년간의 경험이 있습니다. 원래 django 또는 play 프레임 워크로이 애플리케이션을 개발하려고 생각했습니다. 그런 다음 노드를 발견했으며 비 차단 I / O 모델이라는 아이디어는 정말 훌륭하고 매혹적이며 무엇보다도 매우 빠릅니다.
그러나 노드에 어떤 종류의 문제가 있습니까? 프로덕션에서 입증 된 웹 서버입니까? 당신의 경험은 무엇입니까?
들어 때 우아한-FS가 작동하지 않습니다 ... 아니면 그냥 누출이 어디에서 오는 이해합니다. 이 과정을 따르십시오.
(예 : 소켓에 문제가있는 경우 graceful-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 주소 조회를 수행하여 내 경우에는 펀 버브와 관련이 있음을 확인할 수있었습니다.
명령 참조
프로세스가 열린 핸들 수를 결정하려면이 구문을 사용하십시오.
특정 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에서 테스트되었습니다.
많은 연결을 열 것으로 예상되는 경우 (웹 소켓이 좋은 예), 제한을 영구적으로 늘릴 수 있습니다.
파일 : /etc/pam.d/common-session (끝에 추가)
session required pam_limits.so
파일 : /etc/security/limits.conf (끝에 추가하거나 이미 존재하는 경우 편집)
root soft nofile 40000 root hard nofile 100000
ssh에서 nodejs를 다시 시작하고 로그 아웃 / 로그인하십시오.
- 이전 NodeJS에서는 작동하지 않을 수 있습니다. 서버를 다시 시작해야합니다.
- 노드가 다른 uid로 실행되는 경우 대신 사용하십시오.
graceful-fs
Isaac Schlueter (node.js 관리자) 의 모듈을 사용하는 것이 가장 적합한 솔루션 일 것입니다. EMFILE이 발생하면 증분 백 오프를 수행합니다. 내장 fs
모듈 의 드롭 인 대체품으로 사용할 수 있습니다 .
나는 오늘이 문제에 부딪 쳤고 그에 대한 좋은 해결책을 찾지 못했고 그것을 해결할 모듈을 만들었습니다. @fbartho의 스 니펫에서 영감을 얻었지만 fs 모듈을 덮어 쓰지 않기를 원했습니다.
내가 작성한 모듈은 Filequeue 이며 fs처럼 사용합니다.
var Filequeue = require('filequeue');
var fq = new Filequeue(200); // max number of files to open at once
fq.readdir('/Users/xaver/Downloads/xaver/xxx/xxx/', function(err, files) {
if(err) {
throw err;
}
files.forEach(function(file) {
fq.readFile('/Users/xaver/Downloads/xaver/xxx/xxx/' + file, function(err, data) {
// do something here
}
});
});
너무 많은 파일을 읽고 있습니다. 노드는 파일을 비동기 적으로 읽으며 모든 파일을 한 번에 읽습니다. 따라서 아마도 10240 한계를 읽고있을 것입니다.
이것이 작동하는지 확인하십시오.
var fs = require('fs')
var events = require('events')
var util = require('util')
var path = require('path')
var FsPool = module.exports = function(dir) {
events.EventEmitter.call(this)
this.dir = dir;
this.files = [];
this.active = [];
this.threads = 1;
this.on('run', this.runQuta.bind(this))
};
// So will act like an event emitter
util.inherits(FsPool, events.EventEmitter);
FsPool.prototype.runQuta = function() {
if(this.files.length === 0 && this.active.length === 0) {
return this.emit('done');
}
if(this.active.length < this.threads) {
var name = this.files.shift()
this.active.push(name)
var fileName = path.join(this.dir, name);
var self = this;
fs.stat(fileName, function(err, stats) {
if(err)
throw err;
if(stats.isFile()) {
fs.readFile(fileName, function(err, data) {
if(err)
throw err;
self.active.splice(self.active.indexOf(name), 1)
self.emit('file', name, data);
self.emit('run');
});
} else {
self.active.splice(self.active.indexOf(name), 1)
self.emit('dir', name);
self.emit('run');
}
});
}
return this
};
FsPool.prototype.init = function() {
var dir = this.dir;
var self = this;
fs.readdir(dir, function(err, files) {
if(err)
throw err;
self.files = files
self.emit('run');
})
return this
};
var fsPool = new FsPool(__dirname)
fsPool.on('file', function(fileName, fileData) {
console.log('file name: ' + fileName)
console.log('file data: ', fileData.toString('utf8'))
})
fsPool.on('dir', function(dirName) {
console.log('dir name: ' + dirName)
})
fsPool.on('done', function() {
console.log('done')
});
fsPool.init()
우리 모두와 마찬가지로 비동기 I / O의 또 다른 희생자입니다. 비동기 호출을 사용하면 많은 파일을 반복하면 Node.js가 읽을 각 파일에 대해 파일 설명자를 열기 시작한 다음 닫을 때까지 조치를 기다립니다.
서버에서 리소스를 읽을 수있을 때까지 파일 디스크립터는 열려 있습니다. 파일이 작고 읽기 또는 업데이트가 빠르더라도 시간이 걸리지 만 루프가 새 파일 설명자를 여는 것을 멈추지 않습니다. 따라서 파일이 너무 많으면 한도에 도달하고 아름다운 EMFILE 을 얻습니다 .
이 효과를 피하기 위해 큐를 작성하는 솔루션이 하나 있습니다.
Async 을 작성한 사람들 덕분에 매우 유용한 기능이 있습니다. Async.queue 라는 메서드가 있습니다 . 제한이있는 새 대기열을 만든 다음 대기열에 파일 이름을 추가합니다.
참고 : 많은 파일을 열어야하는 경우 현재 열려있는 파일을 저장하고 무한정 다시 열지 않는 것이 좋습니다.
const fs = require('fs')
const async = require("async")
var q = async.queue(function(task, callback) {
console.log(task.filename);
fs.readFile(task.filename,"utf-8",function (err, data_read) {
callback(err,task.filename,data_read);
}
);
}, 4);
var files = [1,2,3,4,5,6,7,8,9,10]
for (var file in files) {
q.push({filename:file+".txt"}, function (err,filename,res) {
console.log(filename + " read");
});
}
각 파일이 대기열에 추가 된 것을 확인할 수 있지만 (console.log 파일 이름) 현재 대기열이 이전에 설정 한 한도 미만인 경우에만 가능합니다.
async.queue는 콜백을 통해 큐의 가용성에 대한 정보를 얻습니다.이 콜백은 데이터 파일을 읽고 수행해야 할 조치가있을 때만 호출됩니다. (fileRead 메소드 참조)
따라서 파일 설명자에 압도 될 수 없습니다.
> node ./queue.js
0.txt
1.txt
2.txt
0.txt read
3.txt
3.txt read
4.txt
2.txt read
5.txt
4.txt read
6.txt
5.txt read
7.txt
1.txt read (biggest file than other)
8.txt
6.txt read
9.txt
7.txt read
8.txt read
9.txt read
I am not sure whether this will help anyone, I started working on a big project with lot of dependencies which threw me the same error. My colleague suggested me to install watchman
using brew and that fixed this problem for me.
brew update
brew install watchman
Edit on 26 June 2019: Github link to watchman
I just finished writing a little snippet of code to solve this problem myself, all of the other solutions appear way too heavyweight and require you to change your program structure.
This solution just stalls any fs.readFile or fs.writeFile calls so that there are no more than a set number in flight at any given time.
// Queuing reads and writes, so your nodejs script doesn't overwhelm system limits catastrophically
global.maxFilesInFlight = 100; // Set this value to some number safeish for your system
var origRead = fs.readFile;
var origWrite = fs.writeFile;
var activeCount = 0;
var pending = [];
var wrapCallback = function(cb){
return function(){
activeCount--;
cb.apply(this,Array.prototype.slice.call(arguments));
if (activeCount < global.maxFilesInFlight && pending.length){
console.log("Processing Pending read/write");
pending.shift()();
}
};
};
fs.readFile = function(){
var args = Array.prototype.slice.call(arguments);
if (activeCount < global.maxFilesInFlight){
if (args[1] instanceof Function){
args[1] = wrapCallback(args[1]);
} else if (args[2] instanceof Function) {
args[2] = wrapCallback(args[2]);
}
activeCount++;
origRead.apply(fs,args);
} else {
console.log("Delaying read:",args[0]);
pending.push(function(){
fs.readFile.apply(fs,args);
});
}
};
fs.writeFile = function(){
var args = Array.prototype.slice.call(arguments);
if (activeCount < global.maxFilesInFlight){
if (args[1] instanceof Function){
args[1] = wrapCallback(args[1]);
} else if (args[2] instanceof Function) {
args[2] = wrapCallback(args[2]);
}
activeCount++;
origWrite.apply(fs,args);
} else {
console.log("Delaying write:",args[0]);
pending.push(function(){
fs.writeFile.apply(fs,args);
});
}
};
With bagpipe, you just need change
FS.readFile(filename, onRealRead);
=>
var bagpipe = new Bagpipe(10);
bagpipe.push(FS.readFile, filename, onRealRead))
The bagpipe help you limit the parallel. more details: https://github.com/JacksonTian/bagpipe
Had the same problem when running the nodemon command so i reduced the name of files open in sublime text and the error dissappeared.
Building on @blak3r's answer, here's a bit of shorthand I use in case it helps other diagnose:
If you're trying to debug a Node.js script that is running out of file descriptors here's a line to give you the output of lsof
used by the node process in question:
openFiles = child_process.execSync(`lsof -p ${process.pid}`);
This will synchronously run lsof
filtered by the current running Node.js process and return the results via buffer.
Then use console.log(openFiles.toString())
to convert the buffer to a string and log the results.
cwait is a general solution for limiting concurrent executions of any functions that return promises.
In your case the code could be something like:
var Promise = require('bluebird');
var cwait = require('cwait');
// Allow max. 10 concurrent file reads.
var queue = new cwait.TaskQueue(Promise, 10);
var read = queue.wrap(Promise.promisify(batchingReadFile));
Promise.map(files, function(filename) {
console.log(filename);
return(read(filename));
})
참고URL : https://stackoverflow.com/questions/8965606/node-and-error-emfile-too-many-open-files
'IT' 카테고리의 다른 글
data.table에서 참조로 행을 삭제하는 방법은 무엇입니까? (0) | 2020.06.18 |
---|---|
Xcode 6-Ad-Hoc 배포를 위해 서명 인증서 / 프로비저닝 프로파일을 선택하는 방법은 무엇입니까? (0) | 2020.06.18 |
NoSQL 사용 사례 [폐쇄] (0) | 2020.06.18 |
Javascript에서 서버를 핑 (ping) 할 수 있습니까? (0) | 2020.06.18 |
VB.NET에서 어떻게 캐스팅해야합니까? (0) | 2020.06.18 |