
Aufstellen:
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache leitet Anfragen mit AJP weiter.
Problem:
Nach einer bestimmten Zeitspanne (nicht konstant, kann zwischen einer oder zwei Stunden oder einem oder mehreren Tagen liegen) wird Tomcat ausfallen. Entweder reagiert es nicht mehr oder es wird die allgemeine Meldung „Dienst vorübergehend nicht verfügbar“ angezeigt.
Diagnose:
Es gibt zwei Server mit demselben Setup. Einer beherbergt eine Website mit hohem Datenverkehr (mehrere Anfragen pro Sekunde), der andere eine mit geringem Datenverkehr (eine Handvoll Anfragen alle paar Minuten). Beide Websites haben völlig unterschiedliche Codebasen, weisen aber ähnliche Probleme auf.
Auf dem ersten Server werden bei Auftreten des Problems langsam alle Threads belegt, bis das Limit (MaxThreads 200) erreicht ist. Ab diesem Zeitpunkt antwortet der Server nicht mehr (und zeigt nach längerer Zeit die Seite „Dienst nicht verfügbar“) an.
Wenn das Problem auf dem zweiten Server auftritt, dauern die Anfragen sehr lange und wenn sie abgeschlossen sind, wird Ihnen nur die Seite „Dienst nicht verfügbar“ angezeigt.
Abgesehen von der Erwähnung des MaxThreads-Problems weisen die Tomcat-Protokolle nicht auf irgendwelche spezifischen Probleme hin, die dies verursachen könnten.
In den Apache-Protokollen sehen wir jedoch zufällige Nachrichten, die sich auf AJP beziehen. Hier ist ein Beispiel für eine zufällige 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)
Das andere Merkwürdige, das uns auf dem Server mit höherem Datenverkehr aufgefallen ist, ist, dass Datenbankabfragen kurz vor dem Auftreten des Problems viel länger dauern als zuvor (2000-5000 ms gegenüber normalerweise 5-50 ms). Dies dauert nur 2-4 Sekunden, bevor die MaxThreads-Meldung angezeigt wird. Ich gehe davon aus, dass dies darauf zurückzuführen ist, dass der Server plötzlich zu viele Daten/Datenverkehr/Threads verarbeiten muss.
Hintergrundinformation:
Diese beiden Server liefen eine ganze Weile ohne Probleme. Die Systeme waren zu dieser Zeit tatsächlich mit jeweils zwei Netzwerkkarten eingerichtet. Sie trennten internen und externen Datenverkehr. Nach einem Netzwerkupgrade haben wir diese Server auf einzelne Netzwerkkarten umgestellt (dies wurde uns aus Sicherheits-/Einfachheitsgründen empfohlen). Nach dieser Änderung traten bei den Servern diese Probleme auf.
Auflösung:
Die naheliegende Lösung wäre, zu einem Setup mit zwei Netzwerkkarten zurückzukehren. Das Problem dabei ist, dass es zu Komplikationen bei der Netzwerkeinrichtung kommen würde, und es scheint, als würde man das Problem ignorieren. Wir würden lieber versuchen, es mit einem Setup mit einer einzelnen Netzwerkkarte zum Laufen zu bringen.
Das Googeln der verschiedenen Fehlermeldungen hat nichts Hilfreiches ergeben (entweder alte Lösungen oder nichts mit unserem Problem verbunden).
Wir haben versucht, die verschiedenen Timeouts anzupassen, aber dadurch lief der Server nur etwas länger, bevor er abstürzte.
Wir sind nicht sicher, wo wir nachsehen sollen, um das Problem genauer zu diagnostizieren. Wir klammern uns immer noch an jeden Strohhalm, um herauszufinden, was 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 statt einer NIC) führt zu Verwirrung oder Durchsatzproblemen.
3) Die Websites selbst (es gibt keinen gemeinsamen Code, es werden keine Plattformen verwendet, nur einfacher Java-Code mit Servlets und JSP)
Aktualisierung 1:
Ich habe den hilfreichen Rat von David Pashley befolgt und während des Problems einen Stacktrace/Threaddump durchgeführt. Dabei habe ich festgestellt, dass sich alle 200 Threads in einem der folgenden Zustände befanden:
"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]
Kurioserweise befand sich 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 zwingt, auf die Fertigstellung zu warten. Aus irgendeinem Grund muss er in diesem Lesezustand stecken bleiben (der Server erholt sich nie von selbst, er muss neu gestartet werden).
Dies lässt darauf schließen, dass es entweder mit dem Netzwerk zwischen dem Server und der Datenbank oder mit der Datenbank selbst zusammenhängen muss. Wir arbeiten weiterhin an der Diagnose, aber jeder Tipp wäre hilfreich.
Antwort1
Es stellte sich heraus, dass diese Version (classes12 – ziemlich alt) des Oracle-Treibers verschiedene Fehler enthielt, die einen Deadlock verursachten (wie im oben zitierten TP-Processor2-Zustand zu sehen). Dieser wurde erst aktiv, als wir auf die neue Umgebung umstellten. Durch ein Upgrade auf die neueste Version (ojdbc14) wurde das Problem auf dem primären Server behoben.
Antwort2
Aus der Beschreibung schließe ich, dass das Problem möglicherweise daran liegt, dass die Datenbankabfragen zu lange dauern. Wenn die Abfragen länger dauern, dauert auch die Anforderung länger und daher werden mehrere davon gleichzeitig ausgeführt. Wie Sie sehen, gehen Ihnen die Tomcat-Threads aus. Wenn Sie das Problem mit der Datenbank lösen, sollte alles in Ordnung sein.
- Holen Sie sich einen Stacktrace, entweder mit jstack oder mit kill -3 $process_id. Sehen Sie, was Ihre Threads tun, wenn sie beendet werden. Wenn sie alle auf die Datenbank warten, ist das ein guter Hinweis auf meine Theorie. Vielleicht warten sie alle auf eine Sperre.
- Installieren Sie LambdaProbe. Es ist von unschätzbarem Wert, um herauszufinden, was Ihr Tomcat tut.
- Aktualisieren Sie Ihren Tomcat. 5.5.8 ist unglaublich alt. Ich glaube, sie sind jetzt bei 5.5.27.
Antwort3
Fügen Sie Ihrem AJP-Connector in /etc/tomcat7/server.xml connectionTimeout und keepAliveTimeout hinzu.
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"
connectionTimeout="10000" keepAliveTimeout="10000" />
Infos zum AJP-Konnektor unterhttps://tomcat.apache.org/tomcat-7.0-doc/config/ajp.html
connectionTimeout = Die Anzahl der Millisekunden, die dieser Connector nach dem Akzeptieren einer Verbindung wartet, bis die Anforderungs-URI-Zeile angezeigt wird. Der Standardwert für AJP-Protokoll-Connectoren ist -1 (d. h. unendlich).
keepAliveTimeout = Die Anzahl der Millisekunden, die dieser Connector auf eine weitere 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 unendlich lange aufrechterhalten. Dies führt zu vielen Threads, die maximale Anzahl an Threads beträgt standardmäßig 200.
Ich empfehle die Installation von psi-probe – einem erweiterten Manager und Monitor für Apache Tomcat, einem Fork von Lambda Probe.https://code.google.com/p/psi-probe/
Antwort4
Ich habe mit mod_proxy bessere Ergebnisse in Bezug auf die Stabilität erzielt als mit mod_ajp. Probieren Sie also diese Lösung aus. Sie ist nicht invasiv – im besten Fall löst sie das Problem und im schlimmsten Fall schließt sie mod_ajp aus.
Abgesehen davon klingt es so, als würden Ihre Tomcats nicht mehr reagieren und alle Anfrage-Threads sind blockiert. Lassen Sie Ihr Entwicklerteam prüfen, was los ist -einen Thread-Dump erstellenund es wird nützlich sein, es ihnen zu überbringen.