J'ai une application qui tourne sur Tomcat et parfois l'erreur ci-dessous:
SEVERE: Socket accept failed
Java.net.SocketException: Too many open files
at Java.net.PlainSocketImpl.socketAccept(Native Method)
at Java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.Java:398)
at Java.net.ServerSocket.implAccept(ServerSocket.Java:522)
at Java.net.ServerSocket.accept(ServerSocket.Java:490)
at org.Apache.Tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.Java:60)
at org.Apache.Tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.Java:216)
at Java.lang.Thread.run(Thread.Java:722)
....
SEVERE: Error processed default web.xml named conf/web.xml at /local/myApp/Apache-Tomcat/conf/web.xml
Java.io.FileNotFoundException: /local/myApp/Apache-Tomcat/conf/web.xml (Too many open files)
at Java.io.FileInputStream.open(Native Method)
at Java.io.FileInputStream.<init>(FileInputStream.Java:138)
at org.Apache.catalina.startup.ContextConfig.getWebXmlSource(ContextConfig.Java:1838)
at org.Apache.catalina.startup.ContextConfig.getGlobalWebXmlSource(ContextConfig.Java:1745)
at org.Apache.catalina.startup.ContextConfig.getDefaultWebXmlFragment(ContextConfig.Java:1418)
at org.Apache.catalina.startup.ContextConfig.webConfig(ContextConfig.Java:1253)
at org.Apache.catalina.startup.ContextConfig.configureStart(ContextConfig.Java:878)
at org.Apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.Java:369)
at org.Apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.Java:119)
at org.Apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.Java:90)
at org.Apache.catalina.core.StandardContext.startInternal(StandardContext.Java:5269)
at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:150)
at org.Apache.catalina.core.StandardContext.reload(StandardContext.Java:3926)
at org.Apache.catalina.loader.WebappLoader.backgroundProcess(WebappLoader.Java:426)
at org.Apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.Java:1345)
at org.Apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.Java:1530)
at org.Apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.Java:1540)
at org.Apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.Java:1540)
at org.Apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.Java:1519)
at Java.lang.Thread.run(Thread.Java:722)
Je vérifie les limites des fichiers ouverts et c’est 1024, mais lorsque je vérifie le nombre de fichiers ouverts de l’application avec lsof, il est presque 200, pourquoi cela se produit-il s’il n’atteint pas la limite? Existe-t-il une autre raison de provoquer cette erreur? Le seul moyen de rétablir le fonctionnement du service consiste à redémarrer Tomcat, existe-t-il un autre moyen de revenir à la normale?
Merci d'avance.
EDIT: Voici le servlet qui traite la méthode doPost, au début, je ne fermais pas tous les flux, est-ce possible? J'ai ajouté la déclaration enfin pour faire cela:
InputStream is = null;
DataInputStream dis = null;
OutputStream os = null;
DataOutputStream dos = null;
String paramName = "";
try {
os = response.getOutputStream();
is = request.getInputStream();
dis = new DataInputStream(is);
dos = new DataOutputStream(os);
.....
}catch (Throwable e) {
LOGGER.error(e.getMessage());
} finally {
if (dis != null) {
dis.close();
}
else if(is != null) {
is.close();
}
if (dos != null) {
dos.close();
}
else if( os != null) {
os.close();
}
}
EDIT2: Après quelques tests, je réalise que si je ferme d’abord le DataInputStream puis le InputStream, j’obtiens dans l’autre partie de la communication un numéro avant le message (je ne sais pas pourquoi). J'ai changé l'ordre de fermeture du flux et il semble que tout va bien. Mais j'ai toujours le problème. Une idée?
finally {
if(is != null) {
try {
is.close();
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
if (dis != null) {
try {
dis.close();
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
if(os != null) {
try {
os.close();
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
if (dos != null) {
try {
dos.close();
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
}
Procédez comme suit pour obtenir le pid, disons 1234, de Tomcat7
ps aux |grep Tomcat7
et ensuite faire
cat /proc/1234/limits
pour lire une ligne comme celle-ci
Max open files 16384 16384 files
Il s'agit du nombre maximal de fichiers ouverts autorisés par Tomcat. Pour l'augmenter, suivez les instructions ci-dessous
Il peut être utile de savoir que vous pouvez modifier la limite de fichiers ouverts en ajoutant ce qui suit à /etc/security/limits.conf
:
* soft nofile 2048 # Set the limit according to your needs
* hard nofile 2048
Ensuite, vous pouvez recharger la configuration en utilisant sysctl -p
sur le shell. Vérifiez cet article .
Juste pour être complet, vous pouvez vérifier quelle est la limite actuelle pour les fichiers ouverts en utilisant: ulimit -n
Cela affichera tous les fichiers ouverts de ce processus.
ls -l /proc/tomcatPID/fd
Cela montrera le nombre de fichiers ouverts.
ls -l /proc/tomcatPID/fd | wc -l
Pour augmenter le nombre de fichiers ouverts, mettez à jour le /etc/Secirity/limits.conf
.
Pour vérifier le nombre de fichiers ouverts spécifiques à Tomcat:
Limite dure: su - Tomcat -c 'ulimit -Hn' -s '/bin/bash'
Limite souple: su - Tomcat -c 'ulimit -Sn' -s '/bin/bash'
Vous pouvez exécuter le script ci-dessous avec un travail maïs pour connaître les détails des fichiers ouverts.
=============================
#!/bin/bash
PID=$(ps -ef|grep Tomcat6|grep -v grep |awk '{print $2}')
value=$(ls -l /proc/$PID/fd | wc -l)
echo `date`@$PID:$value >> /usr/local/filecount.txt
if [ $value -gt 2000 ];
then
printf "\n\n\n\n\n" >> /usr/local/files_report.txt
echo "-------------------------------`date`--Starting Session----------------------" >> /usr/local/files_report.txt
openfiles=$(ls -l /proc/$PID/fd | awk '{print NR,$11 "" >> "/usr/local/files_report.txt"}')
echo "--------------------`date`---Ending Session ------------------------------" >> /usr/local/files_report.txt
fi
=================
La réponse affichée par @gaboroncancio est fondamentalement correcte, mais son conseil sur la manière de rendre les paramètres effectifs n’est pas tout à fait correct. sysctl -p
rechargera /etc/sysctl.conf
, ou le fichier que vous aurez transmis comme argument. Cependant, la commande sysctl
ne reconnaîtra pas le format de /etc/security/limits.conf
.
Pour recharger /etc/security/limits.conf
, il vous suffit de vous déconnecter et de vous reconnecter.
Si ce code provient d'opérations sur le réseau (sockets), je ne suis pas sûr que Java XxxxxStrem possède une relation 1: 1 avec les limites de fichiers du système d'exploitation (ou qu'il en existe une relation). Peut-être besoin de recherches, le message d’exception contient un texte incorrect? Assez souvent dans les logiciels.
Mon intuition dit, nous ne comprenons pas Exception 2, rien dans le code (ou la configuration absente dans la question) n’a de relation.
L'extension du nombre de fichiers du système d'exploitation est limitée lorsque le principal problème est une erreur logicielle (fuite) (mauvaise politique), comme vous l'avez bien compris