2012-11-28 13 views
23

Sto sviluppando un'applicazione web Java EE in Eclipse Juno. Ho configurato Tomcat per utilizzare il pool di connessioni JDBC (org.apache.tomcat.jdbc.pool) insieme al database PostgreSQL. Qui ci sono le configurazioni del mio progetto META-INF/context.xml: Il pool di connessioni JDBC esaurisce le connessioni quando Context reload = "true" è abilitato in Tomcat

<?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> 

La mia applicazione viene distribuita a Tomcat con Eclipse, ed in context.xml di Tomcat una ricaricabile attributo è impostato su "true" per automaticamente ricaricare l'applicazione web, se viene rilevata una modifica:

<Context reloadable="true">

ho notato che ogni volta sopra menzionati ricarica automatica sta accadendo più di 10 connessioni a PostgreSQL db è riservato (perché in context.xml di webapp InitialSize =" 10"). Così, dopo 10 cambia un PSQLException è gettato:

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

Se ricomincio manualmente Tomcat - tutto va bene e solo 10 connessioni sono riservati.

Qualcuno sa come risolvere questo problema, quindi potrebbe essere possibile sviluppare con il set ricaricabile su "true" e non causare il raggruppamento di più connessioni ogni volta che il contesto viene ricaricato?

Apprezzerei qualsiasi aiuto.

P.S. Apache Tomcat versione 7.0.32

+1

Molto probabilmente un duplicato di http://stackoverflow.com/questions/8435359/why-do-connections-persist-when-i-undeploy-a-webapp-using-the-tomcat-7-jdbc-conn – Isaac

+1

@Isaac "È stato corretto da Tomcat 7.0.11", ma ho 7.0.32 e ho ancora lo stesso risultato. Quindi in pratica è un bug? – informatik01

+0

Potrebbe essere una regressione. Se sei assolutamente sicuro che stai liberando tutte le connessioni e il problema persiste, ti chiederei di riaprire la segnalazione di bug. – Isaac

risposta

30

LA SOLUZIONE (tl; dr)

Per risolvere questo problema, aggiungere un attributo closeMethod (documentato here) con il valore "vicino" al elemento Resource nel file context.xml.

Ecco il corretto contenuto del mio file /META-INF/context.xml:

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

Prestare attenzione all'attributo closeMethod. L'ho testato e ora il numero di connessioni viene mantenuto STRETTAMENTE come definito nel file contesto.xml!

NOTA
C'è un momento (relativi a JNDI) che può essere curato. Vedere l'AGGIORNAMENTO 3 per la descrizione completa.


Risposta lunga

OK, ho trovato la soluzione di cui sopra grazie a Apache Tomcat committor Konstantin Kolinko. Ho segnalato this issue come un bug Apache Tomcat su ASF Bugzilla e si è scoperto che non è un bug (vedi AGGIORNAMENTO 1).

=== UPDATE 1 (2012/12/03) alias "Una nuova speranza" ===

Beh, è ​​ancora rivelato essere un bug .Mark Thomas, il release manager Apache Tomcat 7, confirmed che (cito):. PoolCleaner casi

"Questo è un bug perdita di memoria in JDBC-piscina sono ritegno riferimenti al ConnectionPool impedendone la GC'd
...
Questo è stato risolto nel trunk e 7.0.x e sarà incluso in 7.0.34 in poi. "

Quindi, se si dispone di una versione più vecchia di Tomcat (meno di 7.0.34), utilizzare la soluzione di cui sopra, in caso contrario, iniziando con Apache Tomcat versione 7.0.34, non ci dovrebbero essere problemi, come quello che ho descritto. (vedi UPDATE 2)

=== UPDATE 2 (2014/01/13) alias "Il problema colpisce ancora" ===

Sembra che il problema inizialmente descritto nel my bug report è ancora presente anche per l'attuale versione 7.0.50 di Apache Tomcat e l'ho riprodotta anche con Tomcat 7.0.47 (grazie a Miklos Krivan per averlo indicato). Sebbene ora Tomcat a volte riesca a chiudere le connessioni aggiuntive dopo il ricaricamento, ea volte il numero di connessioni aumenta dopo una ricarica e quindi viene mantenuto costante, ma alla fine questo comportamento non è ancora affidabile.

Ho ancora potuto riprodurre il problema inizialmente descritto (anche se non è ancora così facile: può essere correlato alla frequenza di ricariche successive). Sembra che sia solo una questione di tempo, ad esempio se Tomcat ha abbastanza tempo dopo la ricarica, gestisce il pool di connessioni più o meno come dovrebbe. Come ha detto Mark Thomas nel suo comment (citazione): "Come per i documenti per closeMethod, quel metodo esiste unicamente per accelerare la liberazione di risorse che altrimenti sarebbero state liberate da GC." (fine del preventivo), e sembra che la velocità sia il fattore determinante.

Quando si utilizza la soluzione presentata da Konstantin Kolinko (per utilizzare closeMethod = "close"), tutto funziona correttamente e il numero di connessioni riservate viene mantenuto STRETTAMENTE come definito nel file context.xml. Quindi sembra che l'uso di closeMethod = "close" sia l'UNICO modo vero (al momento) per evitare l'esaurimento delle connessioni dopo il ricaricamento del contesto.

=== UPDATE 3 (2014/01/13) aka "Il ritorno del Tomcat Release Manager" ===

il mistero dietro il comportamento descritto nella UPDATE 2 è risolto. Ulteriori dettagli sono stati cancellati ora dopo che ho ricevuto uno reply da Mark Thomas (Tomcat release manager). Spero che questo sia l'ultimo aggiornamento. Così il bug stato infatti fissato come è stato detto nella UPDATE 1. sto inviando la parte essenziale dalla risposta di Mark qui come una citazione (sottolineatura mia):

La perdita di memoria effettiva trovato mentre indaga questo bug ha stato risolto in 7.0.34 in poi come da commenti # 4 a # 6.

Il problema delle connessioni che non vengono chiuse durante il caricamento è il risultato di la specifica J2EE per risorse JNDI e questa parte del rapporto bug non è valida. Sto ripristinando lo stato di questo bug su corretto per riflettere che la perdita di memoria che esisteva è stata corretta.

Per espandere il motivo per cui la mancata chiusura immediata della connessione dopo il ricaricamento non è valida, la specifica J2EE non fornisce alcun meccanismo per il contenitore per indicare alla risorsa che non è più necessaria. Pertanto, tutto il contenitore può fare è chiaro riferimenti alla risorsa e attendere la garbage collection (che attiverà la chiusura del pool e le connessioni associate ). Garbage Collection si verifica a volte in base alla JVM quindi è necessario un intervallo di tempo indeterminato per le connessioni da chiudere dopo un aggiornamento del contesto poiché una raccolta di dati inutili non può verificarsi per qualche tempo.

Tomcat ha aggiunto l'attributo JNDI specifico Tomcat closeMethod che può essere utilizzato per attivare la chiusura esplicita di una risorsa JNDI quando viene arrestato un contesto . Se l'attesa per GC per pulire le risorse non è accettabile, utilizzare semplicemente questo parametro. Tomcat non utilizza questo per impostazione predefinita come , potrebbe avere effetti collaterali inaspettati e indesiderati per alcune risorse JNDI.

Se si desidera visualizzare un meccanismo standard fornito per comunicare alle risorse JNDI che non sono più necessarie, è necessario utilizzare il gruppo di esperti J2EE .

Conclusione

basta usare la soluzione presentata all'inizio di questo post (ma, nel caso, tenere a mente il problema relativo JNDI che possono teoricamente derivano da usarlo).


soluzione alternativa

Michael Osipov suggerito usando il suo CloseableResourceListener, che previene le perdite di memoria causati da risorse aperte sinistro durante undeployment delle applicazioni web. Quindi potresti anche provarlo.


NEGAZIONE
Gli alias per gli aggiornamenti sono stati ispirati dalla serie Star Wars film. Tutti i diritti appartengono ai rispettivi proprietari.

+1

Sfortunatamente Tomcat 7.0.35 ha lo stesso problema ma il valore closeMethod = "close" ha risolto il mio problema. –

+1

Tomcat 7.0.47 ha anche lo stesso problema ma closeMethod = "close" funziona perfettamente. –

+0

@MiklosKrivan Vedere la descrizione finale di questo problema nell'AGGIORNAMENTO 3. – informatik01

Problemi correlati