
Configurar:
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache está encaminhando solicitações usando AJP.
Problema:
Após um determinado período de tempo (nenhuma constante, pode ser entre uma ou duas horas, ou um ou mais dias), o Tomcat irá cair. Ou ele para de responder ou coloca o genérico 'Serviço Temporariamente Indisponível'.
Diagnóstico:
Existem dois servidores com a mesma configuração. Um abriga um site de maior tráfego (várias solicitações por segundo), o outro um site de baixo tráfego (um punhado de solicitações a cada poucos minutos). Ambos os sites têm bases de código completamente diferentes, mas apresentam problemas semelhantes.
No primeiro servidor, quando o problema ocorre, todos os threads começam lentamente a ser ocupados até atingir o limite (MaxThreads 200). Nesse ponto, o servidor não está mais respondendo (e aparece com a página de serviço indisponível após um longo período de tempo).
No segundo servidor, quando o problema ocorre as solicitações demoram muito e quando são concluídas tudo o que você vê é a página de serviço indisponível.
Além da menção ao problema MaxThreads, os logs do Tomcat não indicam nenhum problema específico que possa estar causando isso.
No entanto, nos logs do Apache vemos mensagens aleatórias referentes ao AJP. Aqui está um exemplo de mensagem aleatória que vemos (sem ordem específica):
[error] (70007)The timeout specified has expired: ajp_ilink_receive() can't receive header
[error] (104)Connection reset by peer: ajp_ilink_receive() can't receive header
[error] proxy: AJP: disabled connection for (localhost)
[error] ajp_read_header: ajp_ilink_receive failed
[error] (120006)APR does not understand this error code: proxy: read response failed from 127.0.0.1:8009 (localhost)
[error] ap_proxy_connect_backend disabling worker for (localhost)
A outra coisa estranha que notamos no servidor de maior tráfego é que logo antes do problema começar a acontecer, as consultas ao banco de dados estão demorando muito mais do que antes (2.000 a 5.000 ms versus normalmente 5 a 50 ms). Isso dura apenas 2 a 4 segundos antes que a mensagem MaxThreads apareça. Presumo que isso seja resultado do servidor lidar repentinamente com muitos dados/tráfego/threads.
Informações básicas:
Esses dois servidores estavam funcionando sem problemas há algum tempo. Na verdade, os sistemas foram configurados cada um usando duas NICs durante esse período. Eles separaram o tráfego interno e externo. Após uma atualização de rede, movemos esses servidores para NICs únicos (isso nos foi recomendado por motivos de segurança/simplicidade). Após essa mudança, os servidores começaram a ter esses problemas.
Resolução:
A solução óbvia seria voltar para uma configuração de duas NICs. O problema é que isso causaria algumas complicações na configuração da rede e parece ignorar o problema. Preferimos tentar executá-lo em uma única configuração de NIC.
Pesquisar as várias mensagens de erro no Google não forneceu nada de útil (soluções antigas ou não relacionadas ao nosso problema).
Tentamos ajustar os vários tempos limite, mas isso fez com que o servidor funcionasse um pouco mais antes de morrer.
Não temos certeza de onde procurar para diagnosticar melhor o problema. Ainda estamos tentando descobrir qual poderia ser o problema:
1) A configuração com AJP e Tomcat está incorreta ou desatualizada (ou seja, bugs conhecidos?)
2) A configuração da rede (duas NICs versus uma NIC) está causando confusão ou problemas de rendimento.
3) Os próprios sites (não há código comum, nenhuma plataforma sendo usada, apenas código Java básico com servlets e JSP)
Atualização 1:
Seguindo o conselho útil de David Pashley, fiz um rastreamento de pilha/despejo de thread durante o problema. O que descobri foi que todos os 200 threads estavam em um dos seguintes estados:
"TP-Processor200" daemon prio=1 tid=0x73a4dbf0 nid=0x70dd waiting for monitor entry [0x6d3ef000..0x6d3efeb0]
at oracle.jdbc.pool.OracleConnectionCacheImpl.getActiveSize(OracleConnectionCacheImpl.java:988)
- waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]
"TP-Processor3" daemon prio=1 tid=0x08f142a8 nid=0x652a waiting for monitor entry [0x75c7d000..0x75c7ddb0]
at oracle.jdbc.pool.OracleConnectionCacheImpl.getConnection(OracleConnectionCacheImpl.java:268)
- waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]
Curiosamente, apenas um thread de todos os 200 threads estava neste estado:
"TP-Processor2" daemon prio=1 tid=0x08f135a8 nid=0x6529 runnable [0x75cfe000..0x75cfef30]
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at oracle.net.ns.Packet.receive(Unknown Source)
at oracle.net.ns.DataPacket.receive(Unknown Source)
at oracle.net.ns.NetInputStream.getNextPacket(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
[further stack trace removed for brevity]
Pode ser que o driver Oracle neste thread esteja forçando todos os outros threads a aguardar a conclusão. Por alguma razão, ele deve ficar preso neste estado de leitura (o servidor nunca se recupera sozinho, requer uma reinicialização).
Isso sugere que deve estar relacionado à rede entre o servidor e o banco de dados ou ao próprio banco de dados. Continuamos os esforços de diagnóstico, mas qualquer dica seria útil.
Responder1
Acontece que esta versão (classes12 - bastante antiga) do driver Oracle continha vários bugs que causavam um deadlock (como visto no estado do TP-Processor2 citado acima). Ele não se tornou ativo até mudarmos para o novo ambiente. A atualização para a versão mais recente (ojdbc14) resolveu o problema no servidor primário.
Responder2
Pela descrição, sugiro que o problema pode ser devido à demora muito longa das consultas ao banco de dados. Se as consultas demorarem mais, a solicitação demorará mais e, portanto, você terá mais delas em execução ao mesmo tempo. Como você pode ver, você está ficando sem threads do Tomcat. Ao resolver o problema com o banco de dados, você ficará bem.
- Obtenha um rastreamento de pilha, usando jstack ou kill -3 $process_id. Veja o que seus threads estão fazendo quando morrem. Se todos estão esperando no banco de dados, isso é um bom indicador para minha teoria. Eles podem estar todos esperando por alguma fechadura.
- Instale o LambdaProbe. É inestimável para descobrir o que seu gato está fazendo.
- Atualize seu gato. 5.5.8 é incrivelmente antigo. Acho que eles estão agora em 5.5.27.
Responder3
Adicione connectionTimeout e keepAliveTimeout ao seu conector AJP encontrado em /etc/tomcat7/server.xml.
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"
connectionTimeout="10000" keepAliveTimeout="10000" />
Informações sobre o conector AJP emhttps://tomcat.apache.org/tomcat-7.0-doc/config/ajp.html
connectionTimeout = O número de milissegundos que este Conector irá esperar, após aceitar uma conexão, para que a linha URI da solicitação seja apresentada. O valor padrão para conectores de protocolo AJP é -1 (ou seja, infinito).
keepAliveTimeout = O número de milissegundos que este Conector aguardará por outra solicitação AJP antes de fechar a conexão. O valor padrão é usar o valor que foi configurado para o atributo connectionTimeout.
Se os valores connectionTimeout e keepAliveTimeout não forem definidos, as conexões AJP serão mantidas ativas por infinito. Causando muitos threads, o máximo de threads padrão é 200.
Eu recomendo instalar o psi-probe - um gerenciador e monitor avançado para Apache Tomcat, bifurcado do Lambda Probe.https://code.google.com/p/psi-probe/
Responder4
Tive melhores resultados com mod_proxy em vez de mod_ajp em termos de estabilidade, então tente essa solução. Não é invasivo - na melhor das hipóteses, resolverá o problema e, na pior, excluirá o mod_ajp.
Fora isso, parece que seus Tomcats pararam de responder e todos os threads de solicitação estão amarrados. Peça à sua equipe de desenvolvimento que analise o que está acontecendo -fazendo um despejo de threade entregá-lo a eles será útil.