Apache + Tomcat com problemas de comunicação. Mensagens de erro pouco claras. Desativando sites hospedados no Tomcat

22

Configuração:
Fedora 8
Apache 2.2.8 O
Tomcat 5.5.8
Apache está encaminhando solicitações usando o AJP.

Problema:
Após um determinado período de tempo (nenhuma constante, pode ocorrer entre uma hora ou duas ou um ou mais dias) o Tomcat será desativado. 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 tráfego mais alto (várias solicitações por segundo) e o outro, um de baixo tráfego (um punhado de solicitações a cada poucos minutos). Ambos os sites são bases de código completamente diferentes, mas apresentam problemas semelhantes.

No primeiro servidor, quando o problema ocorre, todos os threads começam a ser ocupados lentamente 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 tempo e, quando 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, estamos vendo 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 tráfego mais alto é que, imediatamente antes do problema começar, as consultas ao banco de dados estão demorando muito mais do que antes (2000-5000 ms versus normalmente 5-50ms). Isso dura apenas 2-4 segundos antes que a mensagem MaxThreads seja exibida. Estou assumindo que isso é resultado do servidor de repente lidar com muitos dados / tráfego / threads.

Informações de plano de fundo:
Esses dois servidores estavam em execução sem problemas há algum tempo. Os sistemas foram realmente configurados, cada um usando duas placas de rede durante esse período. Eles separaram o tráfego interno e o externo. Após uma atualização de rede, movemos esses servidores para NICs únicas (isso nos foi recomendado por motivos de segurança / simplicidade). Após essa alteração, os servidores começaram a ter esses problemas.

Resolução:
a solução óbvia seria retornar à configuração de duas NICs. Os problemas com isso são 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 mais o problema. Ainda estamos tentando entender qual seria o problema:

1) A configuração com o AJP e o Tomcat está incorreta ou desatualizada (ou seja, erros conhecidos?)
2) A configuração da rede (duas NICs versus uma NIC) está causando problemas de confusão ou taxa de transferência.
3) Os sites em si (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 despejo de rastreamento / thread de pilha 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 encadeamento esteja forçando todos os outros encadeamentos a aguardar a conclusão. Por alguma razão, ele deve estar preso nesse estado de leitura (o servidor nunca se recupera sozinho, é necessário reiniciar).

Isso sugere que ele 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.

Jordy Boom
fonte
Primeiro, esta é uma pergunta incrivelmente escrita. Trabalho fantástico nos detalhes! Segundo, você está usando o proxy_ajp ou o mod_jk para conectar os servidores Apache e Tomcat?
Ophidian
Estou usando proxy_ajp para conectar os dois.
21132 Jordy Boom
Faça testes de estresse usando o cerco, joedog.org/siege-home .
paalfe

Respostas:

9

Acontece que esta versão (classes12 - bastante antiga) do driver Oracle tinha vários bugs que causavam um conflito (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 principal.

Jordy Boom
fonte
Isso levou-me a minha solução correta: Eu tinha um bloqueio em um DB-fila ... e nunca recebi qualquer exceção no App-Servidor
cljk
6

A partir da descrição, sugiro que o problema seja devido às consultas do banco de dados que demoram muito tempo. Se as consultas estiverem demorando mais, a solicitação demorará mais e, portanto, você terá mais delas em execução ao mesmo tempo. Como você vê, está ficando sem threads do tomcat. Ao resolver o problema com o banco de dados, você deve ficar bem.

  • Obtenha um rastreamento de pilha, usando jstack ou kill -3 $ process_id. Veja o que seus tópicos estão fazendo quando morrem. Se todos estão esperando no banco de dados, isso é um bom indicador da minha teoria. Todos podem estar esperando por algum bloqueio.
  • Instale o LambdaProbe. É inestimável para descobrir o que seu tomcat está fazendo.
  • Atualize seu tomcat. 5.5.8 é incrivelmente antigo. Eu acho que eles estão agora no 5.5.27.
David Pashley
fonte
David, atualizei a pergunta (consulte a Atualização 1) com novas descobertas com base em sua sugestão de rastreamento de despejo / pilha de encadeamentos.
21132 Jordy Boom
Eu sugiro que seu pool de conexão com o banco de dados seja muito pequeno comparado ao seu valor de conexão máxima do tomcat. Parece que a maioria dos threads está esperando para obter uma conexão com o banco de dados.
David Pashley
A única razão pela qual existem muitos encadeamentos é porque os encadeamentos normalmente usados ​​são deixados aguardando o encadeamento de uma tentativa de leitura do soquete. O número de conexões de banco de dados que estão sendo usadas a qualquer momento varia entre 1 e 3. Nunca há necessidade de mais do que tantas.
21139 Jordy Boom
5

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 em https://tomcat.apache.org/tomcat-7.0-doc/config/ajp.html

  • connectionTimeout = O número de milissegundos que este Conector aguardará, após aceitar uma conexão, para que a linha URI da solicitação seja apresentada. O valor padrão para os conectores do protocolo AJP é -1 (ou seja, infinito).

  • keepAliveTimeout = O número de milissegundos que este Conector aguardará por outra solicitação de AJP antes de fechar a conexão. O valor padrão é usar o valor que foi definido para o atributo connectionTimeout.

Se os valores connectionTimeout e keepAliveTimeout não estiverem definidos, as conexões AJP serão mantidas ativas por infinito. Causando muitos threads, o número máximo de threads padrão é 200.

Eu recomendo instalar o psi-probe - um gerenciador e monitor avançado do Apache Tomcat, bifurcado do Lambda Probe. https://code.google.com/p/psi-probe/

paalfe
fonte
4

Devido à maneira como o AJP funciona, as conexões persistentes entre o apache (usando mod_proxy_ajp ou mod_jk) só podem ser fechadas com segurança pelo cliente . Nesse caso, o cliente é o trabalhador apache que é aberto e mantém uma conexão com o tomcat durante toda a vida útil do processo do trabalhador .

Devido a esse comportamento, você não pode ter mais trabalhadores apache do que os threads de trabalhadores do tomcat. Isso fará com que trabalhadores http adicionais falhem na conexão com o tomcat (como a fila de aceitação está cheia) e marcará seu back-end como BAIXO!

Dave Cheney
fonte
1
Desculpe pelo comentário depois de todos esses anos, mas não foi possível garantir isso definindo o sinalizador max na configuração do ProxyPass para o número de MaxThreads do contêiner do servlet?
Horst Gutmann
2

Eu 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.

Além disso, parece que o seu Tomcats para de responder e todos os threads de solicitação são amarrados. Peça à sua equipe de desenvolvimento o que está acontecendo - pegar um despejo de threads e entregá-lo a eles será útil.

Robert Munteanu
fonte
Fiquei com a impressão de que o mod_proxy tem alguns problemas de escalabilidade, apesar de ser mais fácil de conectar. Parece que a fundação Apache recomenda mod_jk ( wiki.apache.org/tomcat/FAQ/Connectors#Q2 )
Ophidian
Não fornece sessão pegajosa, é verdade. Mas fora isso, nunca tive problemas com isso.
Robert Munteanu
1

A primeira coisa que penso quando ouço que um servidor é executado por um tempo, diminui de repente e começa a ter falhas de serviço é que ele está ficando sem memória RAM e trocando trocas. Não estou claro se as falhas do AJP que você está vendo podem ser conseqüentes de tempos limite, mas não parece completamente irracional; não vejo nenhuma maneira óbvia de se conectar à NIC. De qualquer forma, recomendo que você tenha uma imagem do que está acontecendo com o uso da memória quando esses eventos acontecem.

Se você está ficando sem memória RAM, pode precisar desligar o Apache MaxClientse aumentar o seu ListenBacklog.

A propósito, obrigado por tornar sua pergunta tão bem organizada e completa.

caos
fonte
Quando observo 'top' enquanto isso acontece, o uso da memória permanece bastante consistente. Pelo menos não há picos. Há apenas um breve momento de alto uso da CPU.
Jordy Boom
1

Eu tive erros de log semelhantes no ambiente Redhat com proxy_ajp e Tomcat. Resolvido atualizando o pacote httpd:

yum update httpd

a partir de:

  • httpd-devel-2.2.3-43.el5_5.3.x86_64
  • httpd-2.2.3-43.el5_5.3.x86_64

para:

  • httpd-2.2.3-45.el5_6.3.x86_64
  • httpd-devel-2.2.3-45.el5_6.3.x86_64

Em seguida, reiniciei o apache, seguido pelo Tomcat.

Isso consertou para mim!

Baixo
fonte