Frage Apache + Tomcat hat Probleme bei der Kommunikation. Unklare Fehlermeldungen Herunterbringen von Websites, die unter Tomcat gehostet werden


Konfiguration:
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache leitet Anfragen mit AJP weiter.

Problem:
Nach einer gewissen Zeit (keine Konstante, kann zwischen einer Stunde oder zwei oder einem oder mehreren Tagen liegen) wird Tomcat sinken. Entweder reagiert es nicht mehr oder es wird der generische 'Service vorübergehend nicht verfügbar' angezeigt.

Diagnose:
Es gibt zwei Server mit demselben Setup. Eine beherbergt eine Website mit höherem Traffic (mehrere Anfragen pro Sekunde), die andere eine wenig frequentierte (eine Handvoll Anfragen alle paar Minuten). Beide Websites sind völlig unterschiedliche Codebasen, aber sie weisen ähnliche Probleme auf.

Wenn das Problem auftritt, werden auf dem ersten Server langsam alle Threads gestartet, bis das Limit erreicht ist (MaxThreads 200). Zu diesem Zeitpunkt reagiert der Server nicht mehr (und die Seite "Dienst nicht verfügbar" wird nach einer langen Zeit angezeigt).

Wenn das Problem auf dem zweiten Server auftritt, dauern die Anforderungen sehr lange. Wenn sie fertig sind, sehen Sie nur die Seite "Dienst nicht verfügbar".

Abgesehen von der Erwähnung des MaxThreads-Problems geben die Tomcat-Protokolle keine spezifischen Probleme an, die dies verursachen könnten.

In den Apache-Protokollen sehen wir jedoch zufällige Nachrichten, die sich auf AJP beziehen. Hier ist ein Beispiel einer zufälligen Nachricht, die wir sehen (in keiner bestimmten Reihenfolge):

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

Die andere seltsame Sache, die wir auf dem Server mit höherem Verkehr bemerkt haben, ist, dass Datenbankabfragen viel länger dauern als vorher (2000-5000 ms gegenüber normalerweise 5-50ms), bevor das Problem beginnt. Dies dauert nur 2-4 Sekunden, bevor die MaxThreads-Nachricht angezeigt wird. Ich gehe davon aus, dass dies der Fall ist, wenn der Server plötzlich mit zu viel Daten / Traffic / Threads zu tun hat.

Hintergrundinformation:
Diese beiden Server liefen seit geraumer Zeit problemlos. Die Systeme wurden während dieser Zeit jeweils mit zwei NICs eingerichtet. Sie trennten internen und externen Verkehr. Nach einem Netzwerkupgrade haben wir diese Server auf einzelne NICs verschoben (dies wurde uns aus Gründen der Sicherheit / Einfachheit empfohlen). Nach dieser Änderung begannen die Server mit diesen Problemen.

Auflösung:
Die naheliegende Lösung wäre, zu einem Setup von zwei NICs zurückzukehren. Die Probleme damit sind, dass es einige Komplikationen bei der Netzwerkeinrichtung geben würde, und es scheint, als würde man das Problem ignorieren. Wir würden es am liebsten versuchen und es auf einem einzigen NIC-Setup ausführen lassen.

Das googeln der verschiedenen Fehlermeldungen bot nichts Nützliches (entweder alte Lösungen oder nichts mit unserem Problem zu tun).

Wir haben versucht, die verschiedenen Timeouts anzupassen, aber das ließ den Server nur etwas länger laufen, bevor er starb.

Wir sind nicht sicher, wo wir suchen müssen, um das Problem weiter zu diagnostizieren. Wir greifen immer noch auf Strohhalme, wo das Problem sein könnte:

1) Das Setup mit AJP und Tomcat ist falsch oder veraltet (d. H. Bekannte Fehler?)
2) Das Netzwerk-Setup (zwei NICs versus einer NIC) verursacht Verwirrung oder Durchsatzprobleme.
3) Die Websites selbst (es gibt keinen gemeinsamen Code, keine Plattformen, nur einfacher Java-Code mit Servlets und JSP)

Update 1:
Nach David Pashleys hilfreichem Rat, habe ich während des Problems eine Stack-Trace / Thread-Dump gemacht. Was ich fand, war, dass alle 200 Threads in einem der folgenden Zustände waren:

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

Seltsamerweise war nur ein Thread von allen 200 Threads in diesem Zustand:

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

Es kann sein, dass der Oracle-Treiber in diesem Thread alle anderen Threads dazu zwingt, auf den Abschluss zu warten. Aus irgendeinem Grund muss es in diesem Lesezustand stecken bleiben (der Server erholt sich nie von selbst, es erfordert einen Neustart).

Dies legt nahe, dass es sich entweder um das Netzwerk zwischen dem Server und der Datenbank oder um die Datenbank selbst handeln muss. Wir setzen die Diagnose fort, aber alle Tipps wären hilfreich.


21
2018-06-04 18:40


Ursprung


Zunächst einmal ist dies eine unglaublich geschriebene Frage. Fantastischer Job in den Details! Zweitens, verwenden Sie die proxy_ajp oder mod_jk, um die Apache und Tomcat Server zu verbinden? - Ophidian
Ich benutze proxy_ajp, um die beiden zu verbinden. - Jordy Boom
Stresstests mit Belagerung, joedog.org/siege-home. - paalfe


Antworten:


Es stellt sich heraus, dass diese Version (Klassen12 - ziemlich alt) des Oracle-Treibers verschiedene Fehler enthielt, die einen Deadlock verursachten (wie im oben genannten TP-Prozessor2-Zustand zu sehen ist). Es wurde erst aktiv, als wir in die neue Umgebung wechselten. Das Upgrade auf die neueste Version (ojdbc14) hat das Problem auf dem primären Server behoben.


9
2018-06-10 14:36



Das hat mich dazu geführt meine richtige Lösung: Ich hatte eine Sperre in einer DB-Zeile ... und bekam im App-Server keine Ausnahme - cljk


Aus der Beschreibung würde ich vorschlagen, dass das Problem möglicherweise darin liegt, dass die Datenbankabfragen zu lange dauern. Wenn die Abfragen länger dauern, dauert die Anfrage länger und Sie haben mehr von ihnen auf einmal ausgeführt. Wie Sie sehen, gehen Ihnen die Tomcat-Threads aus. Wenn Sie das Problem mit der Datenbank lösen, sollten Sie in Ordnung sein.

  • Holen Sie sich einen Stack-Trace, entweder mit jstack oder mit kill -3 $ process_id. Sehen Sie, was Ihre Threads tun, wenn es stirbt. Wenn sie alle auf die Datenbank warten, ist das ein guter Hinweis auf meine Theorie. Sie könnten alle auf ein Schloss warten.
  • Installieren Sie LambdaProbe. Es ist von unschätzbarem Wert, um herauszufinden, was Ihr Kater macht.
  • Aktualisieren Sie Ihren Kater. 5.5.8 ist unglaublich alt. Ich denke, sie sind jetzt auf 5.5.27.

6
2018-06-05 08:32



David, ich habe die Frage (siehe Update 1) mit neuen Erkenntnissen aktualisiert, die auf Ihrem Thread-Dump- / Stack-Trace-Vorschlag basieren. - Jordy Boom
Ich würde vorschlagen, dass Ihr Datenbankverbindungspool im Vergleich zu Ihrem Tomcat Max-Verbindungswert zu klein ist. Es scheint, dass die meisten Threads auf eine Datenbankverbindung warten. - David Pashley
Der einzige Grund, warum es so viele Threads gibt, liegt darin, dass die normalerweise verwendeten Threads darauf warten, dass dieser eine Thread versucht, aus dem Socket zu lesen. Die Anzahl der DB-Verbindungen, die zu irgendeiner Zeit verwendet werden, liegt zwischen 1 und 3. Es gibt niemals eine Notwendigkeit für mehr als das viele. - Jordy Boom


Fügen Sie connectionTimeout und keepAliveTimeout zu Ihrem AJP-Connector in /etc/tomcat7/server.xml hinzu.

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

Info über den AJP-Stecker bei https://tomcat.apache.org/tomcat-7.0-doc/config/ajp.html

  • connectionTimeout = Die Anzahl der Millisekunden, die dieser Connector nach dem Akzeptieren einer Verbindung wartet, damit die Anforderungs-URI-Zeile angezeigt wird. Der Standardwert für AJP-Protokollkonnektoren ist -1 (d. H. Unendlich).

  • keepAliveTimeout = Die Anzahl der Millisekunden, die dieser Connector auf eine andere AJP-Anforderung wartet, bevor die Verbindung geschlossen wird. Der Standardwert ist der Wert, der für das Attribut connectionTimeout festgelegt wurde.

Wenn die Werte für connectionTimeout und keepAliveTimeout nicht definiert sind, werden AJP-Verbindungen für unendlich beibehalten. Zu vielen Threads verursachend, beträgt der maximale Thread-Standardwert 200.

Ich empfehle die Installation von Psi-Probe - einem fortgeschrittenen Manager und Monitor für Apache Tomcat, gespalten von Lambda Probe. https://code.google.com/p/psi-probe/


5
2017-07-13 16:12





Aufgrund der Funktionsweise von AJP können die persistenten Verbindungen zwischen Apache (mit mod_proxy_ajp oder mod_jk) nur sicher geschlossen werden vom Kunden. In diesem Fall ist der Client der Apache-Worker, der geöffnet wird, und hält dann eine Verbindung zu Tomcat für die Leben für den Arbeitsprozess.

Aufgrund dieses Verhaltens können Sie nicht mehr Apache-Worker als Tomcat-Worker-Threads haben. Dies führt dazu, dass zusätzliche http-Mitarbeiter keine Verbindung zu Tomcat herstellen können (da die Warteschlange für die Annahme voll ist) und Ihr Backend als DOWN kennzeichnet!


4
2018-06-10 14:46



Sorry für den Kommentar nach all den Jahren, aber konnte dies nicht garantiert werden, indem das Max-Flag innerhalb der ProxyPass-Konfiguration auf die Anzahl der MaxThreads des Servlet-Containers gesetzt wurde? - Horst Gutmann


Ich habe bessere Ergebnisse mit mod_proxy anstelle von mod_ajp in Bezug auf Stabilität, also versuchen Sie diese Lösung. Es ist nicht-invasiv - im besten Fall wird es das Problem lösen und schlimmstenfalls mod_ajp ausschließen.

Ansonsten hört sich das so an, als würden Ihre Tomcats nicht mehr reagieren und alle Anfrage-Threads sind angebunden. Lassen Sie Ihr Entwicklerteam prüfen, was vor sich geht - einen Thread Dump nehmen und es an sie zu liefern wird nützlich sein.


2
2018-06-04 20:01



Ich hatte den Eindruck, dass mod_proxy Probleme mit der Skalierbarkeit hat, obwohl es einfacher ist, sie zu verbinden. Es scheint, dass die Apache-Stiftung mod_jk empfiehlt (wiki.apache.org/tomcat/FAQ/Connectors#Q2) - Ophidian
Es bietet keine klebrige Session, stimmt. Aber ansonsten hatte ich nie Probleme damit. - Robert Munteanu


Das erste, woran ich denke, wenn ich höre, dass ein Server für eine Weile läuft, wird plötzlich langsamer und fängt dann an, Dienstfehler zu haben, weil es keinen RAM mehr hat und keinen Swap mehr hat. Ich bin mir nicht sicher, ob die AJP-Fehler, die Sie sehen, auf Timeouts zurückzuführen sein könnten, aber es scheint nicht völlig unvernünftig zu sein; sehe aber keine offensichtliche Verbindung mit der NIC. In jedem Fall empfehle ich Ihnen, sich ein Bild davon zu machen, was mit Ihrer Speichernutzung geschieht, wenn diese Ereignisse eintreten.

Wenn Ihnen der Arbeitsspeicher knapp wird, müssen Sie möglicherweise Ihren Apache ablehnen MaxClients und erhöhe deine ListenBacklog.

Übrigens, vielen Dank, dass Ihre Frage so gut organisiert und vollständig ist.


1
2018-06-04 19:54



Wenn ich "top" beobachte, während dies geschieht, bleibt die Speichernutzung ziemlich konsistent. Zumindest gibt es keine Stacheln. Es gibt nur einen kurzen Moment mit hoher CPU-Auslastung. - Jordy Boom


Ich hatte ähnliche Log-Fehler in der Redhat-Umgebung mit proxy_ajp und Tomcat. Gelöst durch Aktualisieren des httpd-Pakets:

yum update httpd

von:

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

zu:

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

Dann Neustart Apache, gefolgt von Tomcat neu gestartet.

Das hat es für mich behoben!


1
2018-05-07 19:12