2012-11-28 2 views
23

Ich entwickle eine Java EE-Webanwendung in Eclipse Juno. Ich habe Tomcat so konfiguriert, dass der JDBC-Verbindungspool (org.apache.tomcat.jdbc.pool) zusammen mit der PostgreSQL-Datenbank verwendet wird. Hier sind die Konfigurationen in meinem Projekt META-INF/context.xml: Der JDBC-Verbindungspool hat keine Verbindungen mehr, wenn Context reload = "true" in Tomcat aktiviert ist.

<?xml version="1.0" encoding="UTF-8"?> 
<Context> 
    <!-- Configuration for the Tomcat JDBC Connection Pool --> 
    <Resource name="jdbc/someDB" 
     type="javax.sql.DataSource" 
     auth="Container" 
     factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
     driverClassName="org.postgresql.Driver" 
     url="jdbc:postgresql://localhost:5432/somedb" 
     username="postgres" 
     password="12345" 
     maxActive="100" 
     minIdle="10" 
     initialSize="10" 
     validationQuery="SELECT 1" 
     validationInterval="30000" 
     removeAbandoned="true" 
     removeAbandonedTimeout="60" 
     abandonWhenPercentageFull="50" /> 
</Context> 

Meine Anwendung auf Tomcat bereitgestellt wird mit Eclipse und in Tomcat context.xml ein Attribut wiederaufladbar ist auf „true“, um automatisch laden Sie die Web-Anwendung, wenn eine Änderung erkannt wird:

<Context reloadable="true">

ich, dass über jedes Mal bemerkt habe die automatische Nachladen erwähnte 10 weitere Verbindungen zu PostgreSQL db passiert ist reserviert (weil in Webapp der context.xml Urspr =“ 10 "). So nach 10 ändert ein PSQLException geworfen wird:

org.postgresql.util.PSQLException: FATAL: sorry, too many clients already 
... 

Wenn ich Tomcat manuell neu starten - alles ist in Ordnung und nur 10 Verbindungen sind reserviert.

Kennt jemand den Weg um dieses Problem herum, also könnte es möglich sein, mit reloadable set zu "true" zu entwickeln und nicht jedes Mal, wenn der Kontext neu geladen wird, mehr Verbindungen zu poolen?

Würde mich über jede Hilfe freuen.

P.S. Apache Tomcat Version 7.0.32

+1

Wahrscheinlich ein Duplikat von http://stackoverflow.com/questions/8435359/why-do-connections-persist-when-i-undeploy-a-webapp-using-the-tomcat-7-jdbc-conn – Isaac

+1

@Isaac "Es wurde von Tomcat 7.0.11 korrigiert", aber ich habe 7.0.32 und immer noch das gleiche Ergebnis. Also im Grunde ist es ein Fehler? – informatik01

+0

Könnte eine Regression sein. Wenn Sie absolut sicher sind, dass Sie alle Verbindungen freigeben und das Problem weiterhin auftritt, möchte ich den Fehlerbericht erneut öffnen. – Isaac

Antwort

30

DIE LÖSUNG (tl; dr)

Um dieses Problem zu lösen, fügen Sie ein Attribut closeMethod (dokumentiert here) mit dem Wert "schließen" der Ressourcen Element in der Datei context.xml.

Hier ist der richtige Inhalt meiner /META-INF/context.xml Datei:

<Context> 
    <!-- Configuration for the Tomcat JDBC Connection Pool --> 
    <Resource name="jdbc/someDB" 
     type="javax.sql.DataSource" 
     auth="Container" 
     factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
     driverClassName="org.postgresql.Driver" 
     url="jdbc:postgresql://localhost:5432/somedb" 
     username="postgres" 
     password="12345" 
     maxActive="100" 
     minIdle="10" 
     initialSize="10" 
     validationQuery="SELECT 1" 
     validationInterval="30000" 
     removeAbandoned="true" 
     removeAbandonedTimeout="60" 
     abandonWhenPercentageFull="50" 
     closeMethod="close" /> 
</Context> 

Achten Sie auf das Attribut closeMethod. Ich habe es getestet und jetzt die Anzahl der Verbindungen STRENG gemäß der Definition in der context.xml Datei gehalten!

HINWEIS
Es gibt einen Moment ist (bezogen auf JNDI), die der Pflege genommen werden kann. Eine vollständige Beschreibung finden Sie im UPDATE 3.


Lange Antwort

OK, fand ich die obige Lösung dank Apache Tomcat committor Konstantin Kolinko. Ich berichtete this issue als Apache Tomcat Bug auf ASF Bugzilla und es stellte sich heraus, es ist kein Fehler (siehe UPDATE 1).

=== UPDATE 1 (2012.12.03) aka "A New Hope" ===

Nun, es stellte sich noch ein Fehler erwiesen.Mark Thomas, der Apache Tomcat 7 Release-Manager, confirmed, die (Zitat):.

„Dies ist ein Speicherleck Fehler in jdbc-pool PoolCleaner Instanzen Halte Verweise auf die Connection verhindern, dass es von seinem GC'd .
...
Dies wurde in Stamm und 7.0.x behoben und wird in 7.0.34 weiter enthalten sein. "

Also, wenn Sie eine ältere Version von Tomcat (weniger als 7.0.34) haben, die obige Lösung verwenden, andernfalls mit Apache Tomcat ab Version 7.0.34, sollte es keine Probleme sein, wie ich sie beschrieben. (siehe UPDATE 2)

=== UPDATE 2 (2014.01.13) auch bekannt als "Das Problem schlägt zurück" ===

Es ist wie die Frage scheint zunächst in my bug report beschrieben ist noch vorhanden sogar für die aktuellste Apache Tomcat Version 7.0.50 und ich habe sie auch mit Tomcat 7.0.47 reproduziert (danke an Miklos Krivan für den Hinweis). Obwohl Tomcat es manchmal schafft, nach dem erneuten Laden zusätzliche Verbindungen zu schließen, wird manchmal die Anzahl der Verbindungen nach einem erneuten Laden erhöht und dann konstant gehalten, aber schließlich ist dieses Verhalten immer noch nicht zuverlässig.

Ich konnte immer noch reproduzieren das eingangs beschriebene Problem (obwohl wieder nicht so einfach: es kann mit der Häufigkeit der aufeinander folgenden Neuladungen verbunden sein). Scheint als wäre es nur eine Frage der Zeit, d. H. Wenn Tomcat nach dem erneuten Laden genügend Zeit hat, verwaltet es den Verbindungspool mehr oder weniger wie es sollte. Wie Mark Thomas in seinem comment (Zitat) erwähnt: "Gemäß den Dokumenten für CloseMethod, existiert diese Methode nur, um die Freigabe von Ressourcen zu beschleunigen, die sonst von GC freigegeben würden." (Ende des Zitats), und es scheint, dass die Geschwindigkeit der bestimmende Faktor ist.

Bei Verwendung der von Konstantin Kolinko vorgestellten Lösung (um closeMethod = "close" zu verwenden) funktioniert alles gut, und die Anzahl der reservierten Verbindungen wird wie in der context.xml-Datei definiert STRENG gehalten. So scheint es, dass die Verwendung von closeMethod = "close" der einzig wahre Weg ist, um zu verhindern, dass nach dem erneuten Laden des Kontexts die Verbindungen ausgehen.

=== UPDATE 3 (2014.01.13) auch bekannt als "Rückkehr der Tomcat Release Manager" ===

Das Geheimnis hinter dem Verhalten in der UPDATE 2 beschrieben gelöst. Weitere Details wurden jetzt veröffentlicht, nachdem ich von Mark Thomas (Tomcat Release Manager) eine reply erhalten habe. Ich hoffe, das ist das letzte Update. So der Fehler wurde in der Tat fixiert, wie in der UPDATE erwähnte 1. Ich die wesentliche Teile von Mark Antwort bin Entsendung hier als Zitat (Hervorhebung von mir):

Das tatsächliche Speicherleck gefunden, während dieser Fehler zu untersuchen hat wurde in 7.0.34 nach den Kommentaren # 4 bis # 6 behoben.

Das Problem, dass die Verbindungen beim erneuten Laden nicht geschlossen werden, ist ein Ergebnis der J2EE-Spezifikation für JNDI-Ressourcen, und dieser Teil des Fehlers Bericht ist daher ungültig. Ich stelle den Zustand dieses Bugs auf fest, um anzuzeigen, dass der Speicherverlust, der vorhanden war, behoben wurde.

Um zu erläutern, warum der Fehler zum sofortigen Schließen der Verbindung nach reload ungültig ist, bietet die J2EE-Spezifikation keinen Mechanismus für den Container , um der Ressource mitzuteilen, dass sie nicht mehr benötigt wird. Daher alle der Container kann Referenzen auf die Ressource löschen und warten auf Garbage Collection (die die Schließung des Pools und die zugeordneten Verbindungen auslösen wird). Müllsammlung erfolgt zu bestimmten Zeiten durch die JVM so deshalb dauert es eine unbestimmte Zeit für Verbindungen, die nach einem Kontext reload als Müll Sammlung kann nicht für einige Zeit auftreten geschlossen werden.

Tomcat hat das Tomcat-spezifische JNDI-Attribut closeMethod hinzugefügt, mit dem zum expliziten Schließen einer JNDI-Ressource ausgelöst werden kann, wenn ein -Kontext gestoppt wird. Wenn das Warten auf GC zum Bereinigen von Ressourcen nicht akzeptabel ist, verwenden Sie einfach diesen Parameter. Tomcat verwendet dieses standardmäßig nicht als es kann unerwartete und unerwünschte Nebenwirkungen für einige JNDI-Ressourcen haben.

Wenn Sie Ressourcen einen Standardmechanismus, um zu sehen vorgesehen erzählen JNDI möchten, die sie nicht mehr benötigt, dann müssen Sie die J2EE Expertengruppe einzusetzen.

Fazit

einfach die Lösung am Anfang dieses Beitrags vorgestellt verwenden (aber nur für den Fall, halten Sie das JNDI bezogenes Problem, das kann theoretisch entsteht daraus mit im Auge).


Alternative Lösung

Michael Osipov schlug seine CloseableResourceListener mit, die von links offenen Ressourcen während Undeployment von Web-Anwendungen Speicherlecks verursacht verhindert. So können Sie es auch versuchen.


HAFTUNGSAUSSCHLUSS
Die Aliase für die UPDATES wurden von der Star Wars Filmserie inspiriert. Alle Rechte gehören ihren jeweiligen Eigentümern.

+1

Leider hat Tomcat 7.0.35 die gleichen Probleme, aber der closeMethod = "close" Wert löste mein Problem. –

+1

Tomcat 7.0.47 hat auch die gleichen Probleme, aber die CloseMethod = "close" funktioniert perfekt. –

+0

@MiklosKrivan Siehe die endgültige Beschreibung dieses Problems in der UPDATE 3. – informatik01

Verwandte Themen