web-dev-qa-db-fra.com

Apache + Tomcat ayant des problèmes de communication. Messages d'erreur peu clairs. Faire tomber des sites Web hébergés sous Tomcat

Configuration:
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache transfère les demandes à l'aide d'AJP.

Problème:
Après un certain laps de temps (pas de constante du tout, cela peut prendre entre une heure ou deux, ou un ou plusieurs jours) Tomcat va tomber. Soit il cesse de répondre, soit il met en place le "service temporairement indisponible" générique.

Diagnostic:
Il y a deux serveurs avec la même configuration. L'un héberge un site Web à plus fort trafic (plusieurs demandes par seconde), l'autre un site à faible trafic (une poignée de demandes toutes les quelques minutes). Les deux sites Web sont des bases de code complètement différentes, mais ils présentent des problèmes similaires.

Sur le premier serveur, lorsque le problème se produit, tous les threads commencent lentement à être utilisés jusqu'à ce qu'il atteigne la limite (MaxThreads 200). À ce stade, le serveur ne répond plus (et propose la page de service indisponible après une longue période).

Sur le deuxième serveur, lorsque le problème se produit, les demandes prennent beaucoup de temps et lorsqu'elles sont terminées, tout ce que vous voyez est la page de service indisponible.

Mis à part la mention du problème MaxThreads, les journaux Tomcat n'indiquent aucun problème spécifique pouvant être à l'origine de ce problème.

Cependant, dans les journaux Apache, nous voyons des messages aléatoires faisant référence à AJP. Voici un exemple de message aléatoire que nous voyons (dans aucun ordre spécifique):

[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)

L'autre chose étrange que nous avons remarquée sur le serveur à trafic plus élevé est que juste avant le début du problème, les requêtes de base de données prennent beaucoup plus de temps qu'auparavant (2000-5000 ms contre normalement 5-50ms). Cela ne dure que 2 à 4 secondes avant l'apparition du message MaxThreads. Je suppose que cela est dû au fait que le serveur traite soudainement trop de données/trafic/threads.

Informations générales:
Ces deux serveurs fonctionnaient sans problème depuis un certain temps. Les systèmes ont en fait été configurés chacun à l'aide de deux cartes réseau pendant cette période. Ils ont séparé le trafic interne et externe. Après une mise à niveau du réseau, nous avons déplacé ces serveurs vers des cartes réseau uniques (cela nous a été recommandé pour des raisons de sécurité/simplicité). Après ce changement, les serveurs ont commencé à avoir ces problèmes.

Résolution:
La solution évidente serait de revenir à une configuration de deux cartes réseau. Les problèmes avec cela sont que cela entraînerait des complications avec la configuration du réseau, et cela semble ignorer le problème. Nous préférons essayer de le faire fonctionner sur une seule configuration NIC.

La recherche sur les différents messages d'erreur n'a fourni aucun élément utile (que ce soit d'anciennes solutions ou sans rapport avec notre problème).

Nous avons essayé d'ajuster les différents délais d'attente, mais cela a simplement fait fonctionner le serveur un peu plus longtemps avant de mourir.

Nous ne savons pas où chercher pour diagnostiquer davantage le problème. Nous essayons toujours de comprendre quel pourrait être le problème:

1) La configuration avec AJP et Tomcat est incorrecte ou obsolète (c'est-à-dire des bogues connus?)
2) La configuration du réseau (deux cartes réseau contre une carte réseau) est source de confusion ou de problèmes de débit.
3) Les sites Web eux-mêmes (il n'y a pas de code commun, pas de plates-formes utilisées, juste de base Java code avec servlets et JSP)

Mise à jour 1:
Suite aux conseils utiles de David Pashley, j'ai effectué un suivi de pile/vidage de thread pendant le problème. Ce que j'ai trouvé, c'est que les 200 threads étaient dans l'un des états suivants:

"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]

Curieusement, un seul thread sur les 200 threads était dans cet état:

"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]

Il se peut que le pilote Oracle de ce thread force tous les autres threads à attendre qu'il se termine. Pour une raison quelconque, il doit être bloqué dans cet état de lecture (le serveur ne récupère jamais seul, il nécessite un redémarrage).

Cela suggère qu'il doit être lié soit au réseau entre le serveur et la base de données, soit à la base de données elle-même. Nous poursuivons nos efforts de diagnostic, mais tout conseil serait utile.

22
Jordy Boom

Il s'avère que cette version (classes12 - assez ancienne) du pilote Oracle contenait divers bogues qui provoquaient un blocage (comme vu dans l'état TP-Processor2 cité ci-dessus). Il n'est devenu actif que lorsque nous sommes passés au nouvel environnement. La mise à niveau vers la dernière version (ojdbc14) a résolu le problème sur le serveur principal.

9
Jordy Boom

D'après la description, je suggère que le problème peut être dû au fait que les requêtes de base de données prennent trop de temps. Si les requêtes prennent plus de temps, la demande prendra plus de temps et donc vous en aurez plusieurs en même temps. Comme vous le voyez, vous manquez de threads Tomcat. Lorsque vous résolvez le problème avec la base de données, vous devriez être d'accord.

  • Obtenez une trace de pile, soit en utilisant jstack, soit en utilisant kill -3 $ process_id. Voyez ce que font vos fils quand il meurt. S'ils attendent tous sur la base de données, c'est un bon pointeur vers ma théorie. Ils attendent peut-être tous une serrure.
  • Installez LambdaProbe. C'est précieux pour savoir ce que fait votre Tomcat.
  • Mettez à niveau votre Tomcat. 5.5.8 est incroyablement vieux. Je pense qu'ils sont maintenant sur 5.5.27.
6
David Pashley

Ajoutez connectionTimeout et keepAliveTimeout à votre connecteur AJP trouvé dans /etc/Tomcat7/server.xml.

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" 
           connectionTimeout="10000" keepAliveTimeout="10000" />

Informations sur le connecteur AJP sur https://Tomcat.Apache.org/Tomcat-7.0-doc/config/ajp.html

  • connectionTimeout = Le nombre de millisecondes pendant lequel ce connecteur attendra, après avoir accepté une connexion, que la ligne URI de demande soit présentée. La valeur par défaut pour les connecteurs de protocole AJP est -1 (c'est-à-dire infinie).

  • keepAliveTimeout = Le nombre de millisecondes pendant lequel ce connecteur attendra une autre demande AJP avant de fermer la connexion. La valeur par défaut consiste à utiliser la valeur qui a été définie pour l'attribut connectionTimeout.

Si les valeurs connectionTimeout et keepAliveTimeout ne sont pas définies, les connexions AJP seront maintenues actives pendant une durée infinie. Causant de nombreux threads, le nombre maximum de threads par défaut est de 200.

Je recommande d'installer psi-probe - un gestionnaire et un moniteur avancés pour Apache Tomcat, issu de Lambda Probe. https://code.google.com/p/psi-probe/

5
paalfe

En raison de la façon dont AJP fonctionne, les connexions persistantes entre Apache (à l'aide de mod_proxy_ajp ou mod_jk) ne peuvent être fermées en toute sécurité par le client. Dans ce cas, le client est le travailleur Apache qui s'ouvre, puis détient une connexion à Tomcat pour le durée de vie du processus de travail.

En raison de ce comportement, vous ne pouvez pas avoir plus de travailleurs Apache que de threads de travail Tomcat. Cela entraînera l'échec de la connexion d'autres travailleurs http à Tomcat (car la file d'attente d'acceptation est pleine) et marquera votre backend comme étant DOWN!

4
Dave Cheney

J'ai eu de meilleurs résultats avec mod_proxy au lieu de mod_ajp en termes de stabilité, alors essayez cette solution. Il est non invasif - au mieux, il résoudra le problème et au pire, il exclura mod_ajp.

À part cela, il semble que vos Tomcats cessent de répondre et que tous les threads de demande sont bloqués. Demandez à votre équipe de développement de regarder ce qui se passe - prendre un vidage de thread et le leur fournir sera utile.

2
Robert Munteanu

La première chose à laquelle je pense lorsque j'entends dire qu'un serveur fonctionne pendant un certain temps, ralentit soudainement puis commence à avoir des échecs de service, c'est qu'il est à court de RAM et swashing swap. Je ne suis pas indiquez clairement si les échecs AJP que vous voyez peuvent être dus à des délais d'attente, mais cela ne semble pas complètement déraisonnable; ne voyez pas de manière évidente qu'il se connecterait à la carte réseau. En tout état de cause, je vous recommande d'obtenir un image de ce qui se passe avec votre utilisation de la mémoire lorsque ces événements se produisent.

Si vous manquez de RAM, vous devrez peut-être baisser votre Apache MaxClients et augmenter votre ListenBacklog.

Soit dit en passant, merci d'avoir rendu votre question si bien organisée et complète.

1
chaos

J'ai eu des erreurs de journal similaires dans l'environnement Redhat avec proxy_ajp et Tomcat. Résolu en mettant à jour le package httpd:

yum update httpd

de:

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

à:

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

Redémarrez ensuite Apache, puis redémarrez Tomcat.

Cela m'a arrangé!

1
Bass