IOException: trop de fichiers ouverts
j'essaie de déboguer une fuite de descripteur de fichier dans une webapp Java tournant dans Jetty 7.0.1 sous Linux.
l'application fonctionnait bien depuis un mois environ lorsque les requêtes ont commencé à échouer à cause 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)
j'ai d'abord pensé que le problème était avec le code qui lance le programme externe, mais il utilise commons-exec et je ne vois pas tout ce qui ne va pas avec:
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"));
}
}
Liste des fichiers ouverts sur le serveur, je peut voir un grand nombre de mémoires 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 FIFOs, 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 où regarder ensuite, ou comment obtenir des informations plus détaillées sur ces descripteurs de fichiers?
7 réponses
Votre programme externe ne se comporte pas correctement. Jetez un oeil à pourquoi il ne le fait pas.
le problème vient de votre application Java (ou d'une bibliothèque que vous utilisez).
premier , vous devez lire l'ensemble des sorties (Google pour StreamGobbler), et pronto!
Javadoc dit:
le processus parent utilise ces flux pour alimenter les entrées et les sorties le processus secondaire. Parce que certains autochtones les plates-formes offrent peu de tampon taille pour entrée et sortie standard les flux, à défaut d'écrire rapidement le flux d'entrée ou lecture du flux de sortie de la sous-processus peut entraîner la sous-processus à bloc, et même de impasse.
second , waitFor()
votre processus de résiliation.
Vous devez alors fermer les flux input, output et error.
enfin destroy()
votre Processus.
mes sources:
comme vous utilisez Linux, je soupçonne que vous êtes à court de descripteurs de fichiers. Découvrez ulimit. Voici un article qui décrit le problème: http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/
Je ne sais pas la nature de votre application, mais j'ai vu cette erreur se manifester plusieurs fois en raison d'une fuite de piscine de connexion, de sorte que cela vaudrait la peine de vérifier. Sous Linux, les connexions socket consomment des descripteurs de fichiers ainsi que des fichiers système de fichiers. Juste une pensée.
mis à part le fait d'examiner les causes profondes de problèmes tels que les fuites de fichiers, etc. afin de faire une augmentation légitime de la limite des "fichiers ouverts" et avoir qui persistent à travers les redémarrages, envisager l'édition
/etc/security/limits.conf
en ajoutant quelque chose comme ceci
jetty soft nofile 2048
jetty hard nofile 4096
où "jetty" est le nom d'utilisateur dans ce cas. Pour plus de détails sur les limites.conf, voir http://linux.die.net/man/5/limits.conf
déconnecter et puis se connecter à nouveau et exécuter
ulimit -n
pour vérifier que le changement a eu lieu. Les nouveaux processus de cet utilisateur doivent maintenant se conformer à ce changement. ce lien semble décrire comment appliquer la limite sur les processus déjà en cours, mais je ne l'ai pas essayé.
la limite par défaut 1024 peut être trop basse pour les grandes applications Java.
, Vous pouvez gérer les fds vous-même. L'exec en java renvoie un objet Process. Vérifiez par intermittence si le processus est toujours en cours. Une fois qu'il a terminé fermer les processus stderr, STDIN, et STDOUT flux (par exemple proc.getErrorStream.proche.))( Qui permettront d'atténuer les fuites.
ce problème vient lorsque vous écrivez des données dans de nombreux fichiers simultanément et votre système d'exploitation a une limite fixe de fichiers ouverts. Sous Linux, vous pouvez augmenter la limite des fichiers ouverts.
https://www.tecmint.com/increase-set-open-file-limits-in-linux /
Comment puis-je changer la limite du nombre de fichiers ouverts sous Linux?