web-dev-qa-db-fra.com

IOException: trop de fichiers ouverts

J'essaie de déboguer une fuite de descripteur de fichier dans une application Web Java exécutée dans Jetty 7.0.1 sous Linux.

L'application fonctionnait depuis environ un mois lorsque les demandes ont échoué en raison de trop de fichiers ouverts, et Jetty a dû être redémarré.

Java.io.IOException: Cannot run program [external program]: Java.io.IOException: error=24, Too many open files
    at Java.lang.ProcessBuilder.start(ProcessBuilder.Java:459)
    at Java.lang.Runtime.exec(Runtime.Java:593)
    at org.Apache.commons.exec.launcher.Java13CommandLauncher.exec(Java13CommandLauncher.Java:58)
    at org.Apache.commons.exec.DefaultExecutor.launch(DefaultExecutor.Java:246)

Au début, je pensais que le problème concernait le code qui lance le programme externe, mais il utilise commons-exec et je ne vois rien de mal à cela:

CommandLine command = new CommandLine("/path/to/command")
    .addArgument("...");
ByteArrayOutputStream errorBuffer = new ByteArrayOutputStream();
Executor executor = new DefaultExecutor();
executor.setWatchdog(new ExecuteWatchdog(PROCESS_TIMEOUT));
executor.setStreamHandler(new PumpStreamHandler(null, errorBuffer));
try {
    executor.execute(command);
} catch (ExecuteException executeException) {
    if (executeException.getExitValue() == EXIT_CODE_TIMEOUT) {
        throw new MyCommandException("timeout");
    } else {
        throw new MyCommandException(errorBuffer.toString("UTF-8"));
    }
}

En répertoriant les fichiers ouverts sur le serveur, je peux voir un grand nombre de FIFO:

# lsof -u jetty
...
Java    524 jetty  218w  FIFO        0,6      0t0 19404236 pipe
Java    524 jetty  219r  FIFO        0,6      0t0 19404008 pipe
Java    524 jetty  220r  FIFO        0,6      0t0 19404237 pipe
Java    524 jetty  222r  FIFO        0,6      0t0 19404238 pipe

quand Jetty commence, il n'y a que 10 FIFO, après quelques jours, il y en a des centaines.

Je sais que c'est un peu vague à ce stade, mais avez-vous des suggestions sur la prochaine étape à suivre ou sur la manière d'obtenir des informations plus détaillées sur ces descripteurs de fichiers?

25
Mirko N.

Votre programme externe ne se comporte pas correctement. Jetez un œil à pourquoi il ne fait pas cela.

7

Le problème provient de votre application Java (ou d'une bibliothèque que vous utilisez).

First, vous devriez lire toutes les sorties (Google pour StreamGobbler), et pronto!

Javadoc dit:

Le processus parent utilise ces flux pour alimenter l'entrée et obtenir la sortie de le sous-processus. Parce que certains indigènes les plates-formes ne fournissent qu'un tampon limité taille pour entrée et sortie standard flux, échec d'écrire promptement le flux d'entrée ou lire le flux de sortie du sous-processus peut provoquer le sous-processus à bloquer, et même impasse.

Deuxièmement, waitFor() votre processus à terminer . Vous devez ensuite fermer les flux d'entrée, de sortie et d'erreur.

Enfindestroy() votre processus.

Mes sources:

24
ofavre

Comme vous utilisez Linux, je suppose que vous manquez de descripteurs de fichiers. Découvrez ulimit. Voici un article décrivant le problème: http://www.cyberciti.biz/faq/linux-increase-the-max-number-of-open-files/

8
Greg Smith

En plus d'examiner les problèmes liés à la cause première, tels que les fuites de fichiers, etc. afin d'augmenter de manière légitime le nombre maximal de "fichiers ouverts" et de le conserver lors des redémarrages, envisagez de le modifier

/etc/security/limits.conf

en ajoutant quelque chose comme ça

jetty soft nofile 2048
jetty hard nofile 4096

où "jetée" est le nom d'utilisateur dans ce cas. Pour plus de détails sur limits.conf, voir http://linux.die.net/man/5/limits.conf

déconnectez-vous puis connectez-vous à nouveau et exécutez

ulimit -n

pour vérifier que le changement a bien eu lieu. Les nouveaux processus de cet utilisateur doivent maintenant se conformer à cette modification. Ce lien semble décrire comment appliquer la limite aux processus en cours d'exécution, mais je ne l'ai pas essayée.

La limite par défaut 1024 peut être trop basse pour les applications Java volumineuses.

5
Rami Jaamour

Je ne connais pas la nature de votre application, mais j'ai vu cette erreur se manifester à plusieurs reprises à cause d'une fuite de pool de connexions, il vaudrait donc la peine de la vérifier. Sous Linux, les connexions socket consomment des descripteurs de fichiers ainsi que des fichiers du système de fichiers. Juste une pensée.

5
alasdairg

Vous pouvez gérer les fds vous-même. Le exec en Java renvoie un objet Process. Vérifiez par intermittence si le processus est toujours en cours d'exécution. Une fois terminé, fermez les processus STDERR, STDIN et STDOUT (par exemple, proc.getErrorStream.close ()). Cela atténuera les fuites.

2
allenjsomb

Ce problème survient lorsque vous écrivez des données dans plusieurs fichiers simultanément et que votre système d'exploitation a une limite fixe de fichiers ouverts. Sous Linux, vous pouvez augmenter la limite de fichiers ouverts.

https://www.tecmint.com/increase-set-open-file-limits-in-linux/

Comment changer le nombre de fichiers ouverts dans Linux?

0
Vpn_talent