javascript macos node.js file-descriptor

javascript - nodo y Error: EMFILE, demasiados archivos abiertos



macos node.js (8)

Durante algunos días he buscado una solución de trabajo para un error

Error: EMFILE, too many open files

Parece que muchas personas tienen el mismo problema. La respuesta habitual implica aumentar la cantidad de descriptores de archivos. Entonces, he intentado esto:

sysctl -w kern.maxfiles=20480 ,

El valor predeterminado es 10240. Esto es un poco extraño para mí, porque la cantidad de archivos que manejo en el directorio está por debajo de 10240. Aún más extraño, aún recibo el mismo error después de haber aumentado el número de descriptores de archivos .

Segunda pregunta:

Después de varias búsquedas encontré un problema para el problema de "demasiados archivos abiertos":

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);

Desafortunadamente todavía recibo el mismo error. ¿Qué está mal con este código?

Una última pregunta (soy nuevo en javascript y nodo), estoy en el proceso de desarrollo de una aplicación web con muchas solicitudes para aproximadamente 5000 usuarios diarios. Tengo muchos años de experiencia en programación con otros lenguajes como python y java. así que originalmente pensé en desarrollar esta aplicación con django o play framework. Luego descubrí el nodo y debo decir que la idea del modelo de E / S sin bloqueo es realmente agradable, seductora y, sobre todo, muy rápida.

Pero, ¿qué tipo de problemas debería esperar con el nodo? ¿Es un servidor web probado en producción? ¿Cuáles son tus experiencias?


Acabo de terminar de escribir un pequeño fragmento de código para resolver este problema, todas las demás soluciones parecen demasiado pesadas y requieren que cambie la estructura de su programa.

Esta solución simplemente detiene cualquier llamada a fs.readFile o fs.writeFile para que no haya más de un número establecido en vuelo en un momento dado.

// 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); }); } };


Con la gaita, solo necesitas cambiar

FS.readFile(filename, onRealRead);

=>

var bagpipe = new Bagpipe(10); bagpipe.push(FS.readFile, filename, onRealRead))

La gaita te ayuda a limitar el paralelo. más detalles: https://github.com/JacksonTian/bagpipe


Estás leyendo demasiados archivos. Nodo lee los archivos de forma asíncrona, leerá todos los archivos a la vez. Probablemente estés leyendo el límite de 10240.

Vea si esto funciona:

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()


Me encontré con este problema hoy, y al no encontrar buenas soluciones para él, creé un módulo para abordarlo. Me inspiré en el fragmento de @ fbartho, pero quería evitar sobrescribir el módulo fs.

El módulo que escribí es Filequeue , y lo usas igual que 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 } }); });


Porque cuando graceful-fs no funciona ... o solo quieres entender de dónde viene la fuga. Sigue este proceso

(por ejemplo, graceful-fs no arreglará su vagón si su problema es con sockets).

De Mi Blog Artículo: http://www.blakerobertson.com/devlog/2014/1/11/how-to-determine-whats-causing-error-connect-emfile-nodejs.html

Cómo aislar

Este comando generará el número de identificadores abiertos para los procesos de 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) ....

Observe el: 1023u (última línea) : ese es el manejador del archivo 1024th, que es el máximo predeterminado.

Ahora, mira la última columna. Eso indica qué recurso está abierto. Probablemente verá varias líneas todas con el mismo nombre de recurso. Con suerte, eso ahora te dice dónde buscar en tu código la fuga.

Si no conoce los procesos de múltiples nodos, primero busque qué proceso tiene pid 12211. Eso le dirá el proceso.

En mi caso anterior, noté que había un montón de direcciones IP muy similares. Eran todos 54.236.3.### Al hacer búsquedas de direcciones IP, pude determinar en mi caso que estaba relacionado con pubnub.

Referencia de comando

Use esta sintaxis para determinar cuántos mangos abiertos tiene abierto un proceso ...

Para obtener un recuento de archivos abiertos para un determinado pid

Utilicé este comando para probar la cantidad de archivos que se abrieron después de realizar varios eventos en mi aplicación.

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

¿Cuál es su límite de proceso?

ulimit -a

La línea que desea tendrá el siguiente aspecto: open files (-n) 1024

Cambia permanentemente el límite:

  • probado en Ubuntu 14.04, nodejs v. 7.9

En caso de que espere abrir muchas conexiones (websockets es un buen ejemplo), puede aumentar permanentemente el límite:

  • archivo: /etc/pam.d/common-session (agregar al final)

    session required pam_limits.so

  • file: /etc/security/limits.conf (agregar al final, o editar si ya existe)

    root soft nofile 40000 root hard nofile 100000

  • reinicie su nodejs y logout / login desde ssh.

  • esto puede no funcionar para el NodeJS antiguo que necesitarás para reiniciar el servidor
  • utilizar en lugar de si su nodo se ejecuta con diferentes uid.

Tuve el mismo problema al ejecutar el comando nodemon, así que reduje el nombre de los archivos abiertos en texto sublime y el error desapareció.


Usar el módulo graceful-fs de Isaac Schlueter (node.js manteiner) es probablemente la solución más adecuada. Hace retroceso incremental si se encuentra EMFILE. Se puede usar como un reemplazo directo para el módulo fs incorporado.


cwait es una solución general para limitar las ejecuciones concurrentes de cualquier función que devuelva promesas.

En su caso, el código podría ser algo así como:

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)); })