Démarrage de Tomcat échoue en raison d'un 'java.net.Exception socketexception argument non Valide " sur Mac OS X

Nous avons une application qui s'exécute sur le serveur Tomcat 6 (6.0.35.0 pour être précis), et la plupart de nos ingénieurs sur Mac OS sont d'avoir des problèmes au démarrage de Tomcat en raison de la socketAccept appel dans le Catalina.attendent de la méthode de jeter une exception socketexception:

SEVERE: StandardServer.await: accept:
java.net.SocketException: Invalid argument
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.socketAccept(PlainSocketImpl.java)
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.catalina.core.StandardServer.await(StandardServer.java:431)
at org.apache.catalina.startup.Catalina.await(Catalina.java:676)
at org.apache.catalina.startup.Catalina.start(Catalina.java:628)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
at mycompany.tomcat.startup.ThreadDumpWrapper.main(ThreadDumpWrapper.java:260)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.tanukisoftware.wrapper.WrapperStartStopApp.run(WrapperStartStopApp.java:238)
at java.lang.Thread.run(Thread.java:722)

Cela provoque Tomcat à l'arrêt immédiatement après le démarrage (et pas une petite quantité de rage).
Nous pensons que cela a été avec nous pendant la durée sur Mac OS w/Java 1.7, depuis plusieurs mois, beaucoup d'entre nous ont opté pour Macbook Pros. Jusqu'à maintenant, le seul symptôme était occasionnel de zéro octet réponses de Tomcat, en raison de cette exception s'être jeté sur un socketRead. Les erreurs à ne pas frapper les journaux et nous avions individuellement, il haussa les épaules comme un problème isolé, et seulement trouvé la cause lorsque le problème de démarrage a commencé et j'ai mis une exception socketexception point d'arrêt:

Daemon Thread [http-8080-1] (Suspended (breakpoint at line 47 in SocketException))  
SocketException.<init>(String) line: 47 
SocketInputStream.socketRead0(FileDescriptor, byte[], int, int, int) line: not available [native method] 
SocketInputStream.socketRead0(FileDescriptor, byte[], int, int, int) line: not available  
SocketInputStream.read(byte[], int, int, int) line: 150 
SocketInputStream.read(byte[], int, int) line: 121  
InternalInputBuffer.fill() line: 735  
InternalInputBuffer.parseRequestLine() line: 366  
Http11Processor.process(Socket) line: 814 
Http11Protocol$Http11ConnectionHandler.process(Socket) line: 602  
JIoEndpoint$Worker.run() line: 489  
Thread.run() line: 722  

Pour les arguments:

arg0  FileDescriptor  (id=499)  
fd  1097  
useCount  AtomicInteger  (id=503) 
value 2 
arg1  (id=502)
arg2  0 
arg3  8192  
arg4  20000 

Le problème est le temps sensible. L'augmentation du temps de démarrage en raison de la modification des applications (beaucoup plus de Ressort introspection/singleton frais généraux) semble être le facteur qui provoque cette affecter démarrage de Tomcat; le point de basculement étant d'environ 160 secondes. On peut atténuer le problème en désactivant certains de la non-obligatoire contextes nous n'avons pas besoin au cours du développement afin de réduire les temps de démarrage, mais je préfère trouver la cause.

De configuration de l'Application

Les particularités de la demande sont beaucoup trop complexes pour aller dans trop de détails, mais j'ai l'intuition que cela pourrait être lié à une précédente liaison, donc je vais au moins liste les ports en écoute sur ma machine:

localhost:32000 - Java service wrapper port
*:10001         - RMI registry
*:2322          - Java debug
*:56566         - RMI
*:8180          - Tomcat HTTP connector
*:8543          - Tomcat HTTPS connector
*:2223          - Tomcat Internal HTTP connector (used for cross-server requests)
*:14131         - 'Locking' port to determine if an internal service is running
*:56571         - EhCache RMI
*:56573         - RMI
*:62616         - ActiveMQ broker
*:5001          - SOAPMonitorService
*:8109          - Tomcat shutdown port

Éléments exclu

  • La solution la plus évidente: -Djava.net.preferIPv4Stack=true. J'ai toujours eu cette option configurée
  • Toute récente modification de la configuration de notre base de configuration de l'application, les bibliothèques, les options JVM (il n'y a pas tout)
  • Un JDK de régression. J'ai testé JDK 1.7.0_09, 11, 15, 17 et 21 (le Jdk j'ai eu installé sur ma machine pour la durée)
  • Mise à jour Mac OS. Mac OS 10.7.x et 10.8.0 par 1.8.3 sont affectés
  • Limites des descripteurs de fichiers - augmentation de 5000 à 10000
  • De désactiver IPv6 complètement sur la principale interface ethernet
  • Définition de points d'arrêt, et la suppression de la première contextes d'être touchés par l'exception socketexception (ils sont HTTP sortants appels à des services web). Pas de changement
  • Configuration /etc/hosts de sorte que le nom d'hôte de la machine décide de localhost, et la configuration des options JVM à préférer IPv4 et pas préfèrent les adresses IPv6 (Cette réponse: https://stackoverflow.com/a/16318860/364206)

Pour ceux qui sont intéressés dans la configuration des hôtes, c'est la même chose en tant que par défaut. Je peux reproduire ce sur une Fusion VM w/une installation propre de 10,8:

##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1   localhost
255.255.255.255 broadcasthost
::1             localhost
fe80::1%lo0 localhost

Code Java enquête

En raison de l'apparente du temps de la nature sensible de la question, la définition de points d'arrêt pour résoudre le problème des causes pour ne pas se produire. Comme demandé dans les commentaires, j'ai aussi capturé arg0 pour SocksSocketImpl(PlainSocketImpl).socketAccept(SocketImpl), rien ne semble hors de l'ordinaire.

arg0  SocksSocketImpl  (id=460) 
address InetAddress  (id=465) 
canonicalHostName null  
holder  InetAddress$InetAddressHolder  (id=475) 
address 0 
family  0 
hostName  null  
applicationSetProxy false 
closePending  false 
cmdIn null  
cmdOut  null  
cmdsock null  
CONNECTION_NOT_RESET  0 
CONNECTION_RESET  2 
CONNECTION_RESET_PENDING  1 
external_address  null  
fd  FileDescriptor  (id=713)  
fd  -1  
useCount  AtomicInteger  (id=771) 
value 0 
fdLock  Object  (id=714)  
fdUseCount  0 
localport 0 
port  0 
resetLock Object  (id=716)  
resetState  0 
server  null  
serverPort  1080  
serverSocket  null  
shut_rd false 
shut_wr false 
socket  Socket  (id=718)  
bound false 
closed  false 
closeLock Object  (id=848)  
connected false 
created false 
impl  null  
oldImpl false 
shutIn  false 
shutOut false 
socketInputStream null  
stream  false 
timeout 0 
trafficClass  0 
useV4 false 

Je pense que toutes les discussions où les exceptions sont levées, sont victimes d'un appel antérieur, l'une qui ne risque pas d'entraîner une exception socketexception donc je n'ai pas pu l'attraper. Être en mesure de démarrer Tomcat en réduisant les temps de démarrage me convainc que le déclencheur est probablement une tâche planifiée qui effectue une prise de base de fonctionnement, ce qui affecte les autres opérations de socket.

Qui ne s'explique pas comment et pourquoi cela pourrait affecter plusieurs threads, peu importe ce que nous faisons à cause de ce problème, mystérieux SocketExceptions ne devrait pas remonter à partir de code natif et la cause de ces exceptions simultanément sur plusieurs threads - qui est, les deux fils à la prise de sortants appels de service web, Tomcat attendent d'appel, et de plusieurs TP processeur fils à plusieurs reprises.

JNI code enquête

Donné le message générique, je suppose qu'une EINVAL erreur doit être retourné à partir de l'un des appels système dans le socketAccept JNI code, donc j'ai tracé les appels système menant à l'exception; il n'y a pas EINVAL retourné à partir de tout système d'appel. Donc, je suis allé à l'OpenJDK sources de la recherche de conditions dans le socketAccept code qui permettrait de définir et de jeter un EINVAL, mais je n'arrivais pas à trouver le code qui définit errno à EINVAL, ou des appels NET_ThrowByNameWithLastError, NET_ThrowCurrent ou NET_ThrowNew de manière à lancer une exception socketexception avec ce message d'erreur par défaut.

Autant que le système des appels, nous ne semblons pas à aller aussi loin que le système d'appel accepter:

 PID/THRD        RELATIVE   ELAPSD    CPU SYSCALL(args)    = return
6606/0x2c750d:  221538243       5      0 sigprocmask(0x1, 0x0, 0x14D8BE100)    = 0x0 0
6606/0x2c750d:  221538244       3      0 sigaltstack(0x0, 0x14D8BE0F0, 0x0)     = 0 0
6606/0x2c750d:  221538836      14     10 socket(0x2, 0x1, 0x0)    = 1170 0
6606/0x2c750d:  221538837       3      0 fcntl(0x492, 0x3, 0x4)     = 2 0
6606/0x2c750d:  221538839       3      1 fcntl(0x492, 0x4, 0x6)     = 0 0
6606/0x2c750d:  221538842       5      2 setsockopt(0x492, 0xFFFF, 0x4)     = 0 0
6606/0x2c750d:  221538852       7      4 bind(0x492, 0x14D8BE5D8, 0x10)     = 0 0
6606/0x2c750d:  221538857       5      2 listen(0x492, 0x1, 0x4)    = 0 0
6606/0x2c750d:  221539625       6      2 psynch_cvsignal(0x7FEFBFE00868, 0x10000000200, 0x100)    = 257 0
6606/0x2c750d:  221539633       4      1 write(0x2, "Apr 18, 2013 11:05:35 AM org.apache.catalina.core.StandardServer await\nSEVERE: StandardServer.await: accept: \njava.net.SocketException: Invalid argument\n\tat java.net.PlainSocketImpl.socketAccept(Native Method)\n\tat java.net.PlainSocketImpl.socketAcce", 0x644)    = 1604 0

Donc, je pense le problème se produit dans le délai de la manipulation de code en haut de l'accepter en boucle dans socketAccept, mais je ne pouvais pas trouver tous les cas où NET_Timeout serait mis errno à EINVAL, et de faire en sorte que cette exception socketexception être jeté. Je fais référence à ce code; je suppose que le jdk7u branche est, pour la plupart, que des navires dans l'Oracle JDK:

Aider!

Je ne peux pas trouver quelqu'un dans le monde extérieur touchés par ce problème particulier sur Mac OS, mais presque tout le monde ici est affecté. Il doit y avoir une configuration de l'application qui contribue, mais j'ai épuisé toutes les voies que je peux penser à trouver la cause.

Conseils sur le dépannage ou d'un aperçu sur une cause possible serait très apprécié.

  • Je suis aussi confronté à ce exactement le même problème lors du démarrage de Tomcat sur mon Mac. J'ai aussi une grande application web (uPortal) qui prend environ 100 secondes pour Tomcat pour le démarrage.
  • Génial d'avoir un "moi aussi". Étonnamment peu de choses sur cette ligne.
  • Pourriez-vous récupérer les valeurs qui sont passés à la méthode native et de la poster ici? Elle peut conduire à de nulle part, mais il vaut la peine de vérifier les arguments lorsque vous obtenez une "Argument non Valide" erreur 🙂
  • J'ai ajouté des détails pour arg0 pour SocksSocketImpl(PlainSocketImpl).socketAccept(SocketImpl), mais cette exception peut être levée lorsque apparemment identiques arguments sont passés dans l'
  • Ayant un problème similaire. Cela se bloque Eclipse - j'ai des projets avec un shitload de Pots dans les dépendances (calculée par le plugin), et Eclipse garde une ouverte FD pour chacun d'eux...
  • Puis-je vous demander, pourquoi avez-vous été à la recherche dans src/solaris/native dossier, tout en ayant un problème sur Mac OSX? Je suis actuellement à la recherche de sources natives de Mac, et je me demande si c'est un bon endroit?
  • pas très familier avec le JDK structure, mais il semble que c'est là que le code natif pour BSD trop de vies. J'ai remarqué des instructions conditionnelles pour Linux dans ce code trop, si mon hypothèse est que le Solaris sources sont à la base de tous les systèmes Unix.

InformationsquelleAutor Danny Thomas | 2013-04-24