У нас есть приложение, которое работает на Tomcat 6 (6.0.35.0, если быть точным), и большинство наших инженеров на Mac OS испытывают проблемы с запуском Tomcat из-за вызова socketAccept в методе Catalina.await, бросающего 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)
Это приводит к тому, что Tomcat отключается сразу после запуска (и не имеет большого количества ярости). Мы думаем, что это было с нами на протяжении всего срока действия Mac OS с Java 1.7, за последние несколько месяцев многие из нас перешли на Macbook Pros. До сих пор единственным симптомом были случайные ответы с нулевым байтом от Tomcat, из-за этого исключения также бросали на socketRead. Ошибки не попадают в журналы, и мы индивидуально пожали плечами, как изолированная проблема, и обнаружили причину только при запуске проблемы с запуском, и я установил точку останова SocketException:
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  
Для аргументов:
arg0  FileDescriptor  (id=499)  
  fd  1097  
  useCount  AtomicInteger  (id=503) 
    value 2 
arg1  (id=502)
arg2  0 
arg3  8192  
arg4  20000 
Проблема чувствительна к времени. Увеличение времени запуска из-за изменений в приложениях (более чем Spring introspection/singleton overhead), по-видимому, является фактором, который заставляет это влиять на запуск Tomcat; точка опрокидывания составляет около 160 секунд. Мы можем смягчить эту проблему, отключив некоторые необязательные контексты, которые нам не нужны во время разработки, чтобы сократить время запуска, но я бы предпочел найти основную причину.
Конфигурация приложения
Специфика приложения слишком сложна, чтобы входить в слишком подробные сведения, но у меня есть догадка, что это может относиться к раннему связыванию, поэтому я, по крайней мере, буду перечислять прослушивающие порты на моей машине:
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
Элементы исключены
-  Наиболее очевидное решение: -Djava.net.preferIPv4Stack=true. У меня всегда был настроен этот параметр.
- Любое недавнее изменение конфигурации для нашей базовой конфигурации приложения, библиотек, параметров JVM (их нет)
- Регрессия JDK. Я тестировал JDK 1.7.0_09, 11, 15, 17 и 21 (JDK, которые я установил на своей машине в течение всего времени).
- Обновление ОС Mac. Mac OS 10.7.x и от 10.8.0 до 1.8.3 затронуты
-  Пределы дескриптора файла - увеличены с 5000до10000
- Отключение IPv6 полностью на главном интерфейсе Ethernet
- Установка контрольных точек и удаление первых контекстов, на которые влияет SocketException (они являются исходящими HTTP-вызовами веб-служб). Без изменений
-  Конфигурирование /etc/hosts, так что имя хоста компьютера разрешается на localhost и настраивает параметры JVM для предпочтения IPv4 и не предпочитает адреса IPv6 (этот ответ: qaru.site/info/187549/...)
Для тех, кто интересуется конфигурацией хостов, он аналогичен по умолчанию. Я могу воспроизвести это на Fusion VM с чистой установкой 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
Исследование Java-кода
Из-за очевидного чувствительного к времени характера проблемы установка контрольных точек для устранения неполадок не приводит к ее возникновению. В соответствии с просьбой в комментариях я также взял arg0 для SocksSocketImpl(PlainSocketImpl).socketAccept(SocketImpl), ничего не выглядит необычным.
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 
Я думаю, что все потоки, в которых выбрасываются исключения, являются жертвами более раннего вызова, который не приводит к исключению SocketException, поэтому я не смог его поймать. Возможность запуска Tomcat за счет сокращения времени запуска убеждает меня в том, что триггер, вероятно, представляет собой запланированную задачу, которая выполняет операцию на основе сокетов, которая затем влияет на другие операции сокета.
Это не объясняет, как и почему это может повлиять на несколько потоков, независимо от того, что мы делаем, чтобы вызвать это условие, таинственные SocketExceptions не должны пузыриться из собственного кода и вызывать эти исключения одновременно на нескольких потоках - это, два потока, вызывающие исходящие вызовы веб-сервисов, ожидание вызова Tomcat и несколько потоков процессора TP.
Исследование кода JNI
Учитывая общее сообщение, я предположил, что ошибка из EINVAL должна быть возвращена из одного из системных вызовов в коде socketSccept JNI, поэтому я проследил системные вызовы, ведущие к исключению; там нет EINVAL, возвращаемого с любого системного вызова. Итак, я пошел в источники OpenJDK, ища условия в коде socketAccept, который бы установил, а затем выбросил EINVAL, но я также не смог найти код, который устанавливает errno в EINVAL, или вызывает NET_ThrowByNameWithLastError, NET_ThrowCurrent или NET_ThrowNew таким образом, чтобы это исключение SocketException с этим сообщением об ошибке по умолчанию.
Что касается системных вызовов, мы, кажется, не дошли до системного вызова accept:
 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
Итак, я думаю, что проблема возникает в коде обработки тайм-аута в верхней части цикла accept в socketAccept, но я не мог найти случай, когда NET_Timeout установил errno в EINVAL, и в результате возникает это SocketException. Я имею в виду этот код; Я полагаю, что ветвь jdk7u по большей части является судом в Oracle JDK:
- http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/d4bf5c15837c/src/solaris/native/java/net/PlainSocketImpl.c
- http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/d4bf5c15837c/src/solaris/native/java/net/bsd_close.c
- http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/d4bf5c15837c/src/solaris/native/java/net/net_util_md.c
Помогите!
Я не могу найти никого во внешнем мире, затронутого этой конкретной проблемой в Mac OS, но почти все здесь затронуты. Должна быть какая-то конфигурация приложения, которая способствует, но я исчерпал все возможности, которые я могу придумать, чтобы найти основную причину.
Указатели на устранение неполадок или понимание возможной причины были бы очень оценены.