Estouro de 32 bits baseado em tempo em Java? Ou SLES11?

4

Este é o Tomcat 6.0.18, o Java 1.7.0_03 (32 bits) e o SLES11 SP2 (64 bits). Quanto às informações do kernel:

$ uname -a
Linux server-1 3.0.13-0.27-default #1 SMP Wed Feb 15 13:33:49 UTC 2012 (d73692b) x86_64 x86_64 x86_64 GNU/Linux

Estávamos fazendo um teste de carga e longevidade em três servidores. Nas três máquinas separadas, o Tomcat saiu dentro de um segundo de 2 ^ 32 milissegundos (49+ dias) de quando cada Tomcat foi iniciado. Em cada máquina, dois encadeamentos produziram rastreios de pilha antes que a JVM saia (o próprio Tomcat chama System.exit(1) quando obtém o SocketTimeoutException , e é por isso que a JVM sai).

Um thread é o que (por padrão) escuta na porta 8005 para o comando shutdown (verificado isso olhando para a origem do Tomcat):

Jun 22, 2012 9:10:15 AM org.apache.catalina.core.StandardServer await
SEVERE: StandardServer.await: accept: 
java.net.SocketTimeoutException: Accept timed out
      at java.net.PlainSocketImpl.socketAccept(Native Method)
      at java.net.AbstractPlainSocketImpl.accept(Unknown Source)
      at java.net.ServerSocket.implAccept(Unknown Source)
      at java.net.ServerSocket.accept(Unknown Source)
      at org.apache.catalina.core.StandardServer.await(StandardServer.java:389)
      at org.apache.catalina.startup.Catalina.await(Catalina.java:642)
      at org.apache.catalina.startup.Catalina.start(Catalina.java:602)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
      at java.lang.reflect.Method.invoke(Unknown Source)
      at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
      at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)

O outro segmento é (acreditamos, embora não tenhamos verificado a origem do Tomcat para verificar) aquele que lida com as conexões da porta de entrada 8080:

Jun 22, 2012 9:10:15 AM org.apache.jk.common.ChannelSocket acceptConnections
WARNING: Exception executing accept
java.net.SocketTimeoutException: Accept timed out
      at java.net.PlainSocketImpl.socketAccept(Native Method)
      at java.net.AbstractPlainSocketImpl.accept(Unknown Source)
      at java.net.ServerSocket.implAccept(Unknown Source)
      at java.net.ServerSocket.accept(Unknown Source)
      at org.apache.jk.common.ChannelSocket.accept(ChannelSocket.java:307)
      at org.apache.jk.common.ChannelSocket.acceptConnections(ChannelSocket.java:661)
      at org.apache.jk.common.ChannelSocket$SocketAcceptor.runIt(ChannelSocket.java:872)
      at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690)
      at java.lang.Thread.run(Unknown Source)

O Tomcat não está fazendo nada maluco. No primeiro caso, é apenas um while (true) loop que recebe um Socket chamando ServerSocket.accept() e as accept() chamam as bombas.

Alguma idéia de por que isso está acontecendo e do que eu poderia tentar analisar para descobrir como evitá-lo no futuro?

Note que enquanto o Tomcat estava rodando por 2 ^ 32 milissegundos, o sistema já estava ativo quando o Tomcat foi iniciado. Claro que isso não descarta alguma variável de processo que foi criada quando o Tomcat começou a se envolver.

    
por QuantumMechanic 27.06.2012 / 23:50

2 respostas

4

Eu tenho visto recentemente este problema bem e parece ser isolado a uma alteração feita no Oracle JVM de 32 bits entre Java 6 e 7. No Linux, rodando a 32-bit Java 7 VM com strace mostra a seguinte chamada do sistema quando ServerSocket.accept () é invocado sem ter definido SO_TIMEOUT:

32369 poll([{fd=5, events=POLLIN|POLLERR}], 1, 4294967295 <unfinished ...>

A chamada para poll () passa um valor de tempo limite de 2 ^ 32 milissegundos (4294967295), em vez do valor negativo esperado que indicaria um tempo limite infinito. Isso eventualmente faz com que ServerSocket.accept () lance uma SocketTimeoutException, que faz com que o código de inicialização do Tomcat execute um desligamento do servidor. Essa parte específica do Tomcat nunca espera que uma SocketTimeoutException seja lançada pelo ServerSocket.accept.

É mais fácil reproduzir esse problema se a chamada para poll () puder ser manipulada para que você não precise aguardar 2 ^ 32 milissegundos. Isso pode ser feito no Linux, substituindo a chamada do sistema de pesquisa. Um método para fazer isso envolve o uso da diretiva LD_PRELOAD para carregar uma versão modificada da pesquisa. Alguns exemplos de código que mostram essa ideia podem ser encontrados no link . Infelizmente, ele não substitui a pesquisa, mas pode ser facilmente estendido para isso.

    
por 04.02.2014 / 00:24
3

Eu estava passando pelo mesmo problema usando o Tomcat 7.0.35 com o Java 1.7.0_10 (32 bits) em um Debian Linux de 64 bits.

No meu caso, atualizar e usar o JDK de 64 bits resolveu esse problema

    
por 28.01.2014 / 08:38