Die Analyse Connection Closed Exception in Spring/JPA/Mysql/Tomcat-app
PROBLEM
Vor kurzem war ich beauftragt, ein Java-web-Anwendung mit dem code, der bereits geschrieben und an Ort und Stelle. Die app empfängt die mäßig hohen traffic und hat peak-Stunden-Verkehr zwischen 11 Uhr bis 3 Uhr jeden Tag.
Die Anwendung verwendet Spring, JPA(Hibernate), MYSQL-DB.
Der Frühling wurde so konfiguriert, tomcat, jdbc-connection-pool, um verbindungen mit der DB.
(Details der Konfiguration am Ende der post)
In den letzten Tagen, während der Anwendung Spitzenlastzeiten, die Anwendung wurde hinunter durch tomcat geht nicht mehr auf Anfragen. Es ist erforderlich, tomcat neu gestartet werden, mehrere Male.
Gehen durch die tomcat catalina.aus Protokollen, die ich bemerkte, eine ganze Menge
Caused by: java.sql.SQLException: Connection has already been closed.
at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:117)
at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:109)
at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:80)
at com.sun.proxy.$Proxy28.prepareStatement(Unknown Source)
at org.hibernate.jdbc.AbstractBatcher.getPreparedStatement(AbstractBatcher.java:505)
at org.hibernate.jdbc.AbstractBatcher.getPreparedStatement(AbstractBatcher.java:423)
at org.hibernate.jdbc.AbstractBatcher.prepareQueryStatement(AbstractBatcher.java:139)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1547)
at org.hibernate.loader.Loader.doQuery(Loader.java:673)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
at org.hibernate.loader.Loader.loadCollection(Loader.java:1994)
... 115 more
Diese treten Häufig kurz vor dem Absturz.
Weiter vor, diese Ausnahmen, die ich bemerkt, eine ganze Reihe von Verbindungen aufgegeben, kurz bevor die Verbindung Geschlossen Ausnahmen.
WARNING: Connection has been abandoned PooledConnection[com.mysql.jdbc.Connection@543c2ab5]:java.lang.Exception
at org.apache.tomcat.jdbc.pool.ConnectionPool.getThreadDump(ConnectionPool.java:1065)
at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:782)
at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:618)
at org.apache.tomcat.jdbc.pool.ConnectionPool.getConnection(ConnectionPool.java:188)
at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:128)
at org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider.getConnection(InjectedDataSourceConnectionProvider.java:47)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:423)
at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:144)
at org.hibernate.jdbc.AbstractBatcher.prepareQueryStatement(AbstractBatcher.java:139)
Diese scheinen Häufig, kurz bevor die Verbindung Geschlossen Ausnahmen. Und diese scheinen die ersten Symptome von drohendem Unheil in den logs.
ANALYSE
Gehen durch die logs, die ich sehen, ob es irgendeine Verbindung gibt pool-Konfiguration/mysql-Konfiguration, die möglicherweise das Problem verursacht.
Ging durch ein paar exzellente Artikel, die zeigen, dass tuning den pool für Produktion und Umwelt. Links Eins & Zwei
Gehen durch diesen Artikel, habe ich bemerkt, dass:
- Die folgende Zeile in JHanik Artikel (link 1) erwähnt diese
Einstellung der Wert von abandonWhenPercentageFull 100 würde bedeuten, dass die verbindungen nicht > als aufgegeben, es sei denn, wir haben erreicht, unsere maxActive begrenzen.
Ich dachte, dies könnte wichtig sein, in meinem Fall, denn ich sehe eine Menge von verbindungen aufgegeben.
- Meine max_connections Einstellung nicht übereinstimmt, was empfohlen wird (link 2)
mysql max_connections sollte gleich max_active+max_idle
, WAS ICH VERSUCHT HABE
So, wie pro die Empfehlungen aus dem Artikel habe ich die folgenden zwei Dinge:
- Geändert abandonWhenPercentageFull zu 100
- In meinem MYSQL-server, max_connections gesetzt wurde als 500. Erhöhte it-600
In meinem Verbindungs-pool-Einstellungen, max_active war 200 und max_idle war 50.
Verändert es max_active=350, max_idle = 250
DIES NICHT HILFT,
Den nächsten Tag, der folgende Beobachtungen gemacht wurden, während der Stoßzeiten:
- Tomcat nicht nach unten gehen. Die app blieb während der Stoßzeiten.
Jedoch ist die Leistung immer schlechter und dann ist die app kaum nutzbar, auch wenn es nicht wirklich nach unten gehen. - DB-Connection-pool, aber erhöht in der Größe, völlig verwertet, und ich konnte sehen, 350 aktive verbindungen zu der DB an einem Punkt.
ENDLICH, MEINE FRAGE:
Er klar sieht aus wie es gibt Probleme mit der Art, wie DB-verbindungen hergestellt sind aus dem app-server.
Also ich habe zwei Richtungen zu nehmen, diese Analyse weiterleiten.
Meine Frage ist welche von diesen sollte ich nehmen?
1. Das Problem ist nicht mit dem Verbindungs-pool-Einstellungen. Der code ist was das Problem verursacht
Möglicherweise gibt es stellen im code, wo DB-verbindungen werden nicht geschlossen. Was ist die Ursache der hohen Anzahl an verbindungen öffnen.
Verwendet der code eine GenericDao die extended in jede Dao-Klasse. Die GenericDao verwendet Spring JpaTemplate zu Holen EntityManager-Instanz, die wiederum für alle DB-Operationen. Mein Verständnis ist mit dem JpaTemplate behandelt die nitty gritty der Schließung DB-verbindungen intern.
Also, wo genau soll ich suchen für eine mögliche undichte Verbindung?
2. Das Problem mit den Anschlüssen pool - /mysql-config-Parameter. Allerdings werden die Optimierungen, die ich haben muss abgestimmt werden, weitere
Wenn ja, welche Parameter sollte ich suchen?
Sollte ich sammeln einige Daten zu verwenden, um zu bestimmen geeigneter Werte für meine connection pool. (Für z.B. für max_active, max_idle, max_connections)
Nachtrag: Vollständige Verbindungs-Pool-Konfiguration
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://xx.xx.xx.xx" />
<property name="username" value="xxxx" />
<property name="password" value="xxxx" />
<property name="initialSize" value="10" />
<property name="maxActive" value="350" />
<property name="maxIdle" value="250" />
<property name="minIdle" value="90" />
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<property name="removeAbandoned" value="true" />
<property name="removeAbandonedTimeout" value="60" />
<property name="abandonWhenPercentageFull" value="100" />
<property name="testOnBorrow" value="true" />
<property name="validationQuery" value="SELECT 1" />
<property name="validationInterval" value="30000" />
<property name="logAbandoned" value="true" />
<property name="jmxEnabled" value="true" />
</bean>
InformationsquelleAutor ncmadhan | 2014-02-11
Du musst angemeldet sein, um einen Kommentar abzugeben.
Dies ist beklagenswert spät für die OP, aber vielleicht hilft es ja jemand anderem in der Zukunft:
Ich lief in etwas, ähnlich wie diese in einer Produktionsumgebung mit langlaufende batch-jobs. Das problem ist, wenn Ihr code benötigt, eine Verbindung, die länger als die angegebene Zeit-Eigenschaft:
name="removeAbandonedTimeout" value="60
und aktiviert haben:
<property name="removeAbandoned" value="true" />
dann wird die Verbindung getrennt, während der Verarbeitung nach 60 Sekunden. Ein möglicher workaround (hat bei mir nicht funktioniert), ist die Aktivierung der Abfangjäger:
jdbcInterceptors="ResetAbandonedTimer"
Damit setzt sich der verlassene timer für die Verbindung für alle Lesen/schreiben Auftritt. Leider in meinem Fall, die Verarbeitung würde, manchmal noch länger dauert als der timeout, bevor irgendetwas gelesen wurde,/in die Datenbank geschrieben. So war ich gezwungen, entweder stoßen die timeout-Länge, oder deaktivieren Sie die removeAbandonded (ich entschied mich für die erste Lösung).
Hoffe, dies hilft jemand anderes, wenn Sie in etwas laufen ähnlich!
Das hat mir wirklich geholfen zu verstehen, die Semantik einer Auswirkungen der "removeAbandoned". Aus meinen Beobachtungen vermute ich, dass die abandonedTimeout kumuliert über mehrere Mietverträge der gleichen Verbindung.
InformationsquelleAutor Ryan P.
Vor kurzem wurde ich gebeten, zu untersuchen, warum die Produktion system geht manchmal runter. Ich wollte meine Erkenntnisse da es sich um eine Korrelation der Ereignisse, die eine JVM tomcat-Anwendung mit JDBC-Probleme, wie oben beschrieben, um tatsächlich zum Absturz der app. Dies ist mit Hilfe von mysql als backend, also wahrscheinlich am nützlichsten für dieses Szenario, aber wenn das Thema trifft auf eine andere Plattform, die Ursache dürfte die gleiche sein.
, Indem Sie einfach die erste Verbindung geschlossen bedeutet nicht, die Anwendung ist gebrochen
Dies ist unter einer grails-Anwendung, sondern werden im Verhältnis zu allen JVM-apps mit:
tomcat/context.xml
db-Konfiguration feststellen, sehr kleine db-pool undremoveAbandonedTimeout="10"
Ihr habt Recht, wir wollen die Dinge zu brechen,Einem Quarz-job, der jede minute ausgeführt, nicht, dass es darauf ankommt, die app, die ich denke, stirbt beim ersten Versuch:
Nun unser testService mit Kommentaren, so befolgen Sie bitte die Kommentare:
Ist es nur, wenn die Abfrage dauert länger als erwartet Zeit, aber es muss ein weiteres element, die Abfrage selbst muss dann Treffer sitzen auf MYSQL auch wenn es getötet wird. MYSQL frisst es Weg der Verarbeitung.
Ich denke, was passiert ist
Wenn zu dieser Zeit job1 noch nicht abgeschlossen hat, dann haben wir nichts mehr in den pool gut app ist einfach jetzt pleite.. jdbc-Fehler geworfen etc.. nie dagegen, wenn es abgeschlossen ist, nach dem Absturz..
Können Sie überwachen, was Los ist, indem überprüfung mysql
Es schien zu laufen für eine längere Zeit, das geht gegen das, was Sie vorgeschlagen haben, sollte dieser Wert zu tun, aber dann wieder, vielleicht das ist nicht wirklich basierend auf diese und bezieht sich auf ein problem an anderer Stelle.
Während der Prüfung aufgefallen, gab es zwei Staaten: Daten Senden /Senden an client:
Sseconds später:
Kann es sein, dass ein Skript erstellt werden muss zur überwachung der Prozess-Liste und vielleicht eine tiefere ResultSet mit genauen Abfragen ausführen, um herauszufinden, welche Ihrer Abfragen Veranstaltungen ist das töten Ihrer app
InformationsquelleAutor Vahid
Dies ist wahrscheinlich die Wurzel des Problems ist, sollten Sie nicht verwenden die
JpaTemplate
um dieEntityManager
dies wird Ihnen un-unmanagedEntitymanager
. In der Tat, sollten Sie nicht verwendenJpaTemplate
überhaupt.Ist es empfehlenswert, zu schreiben, daos, basierend auf der Ebene
EntityManager
API und einfach zu injizieren dieEntityManager
wie Sie es normalerweise tun würde (mit@PersistenceContext
).Wenn Sie wirklich wollen, verwenden Sie die
JpaTemplate
verwenden Sie dieexecute
- Methode, und übergeben Sie eineJpaCallback
die geben Sie eine verwalteteEntityManager
.Stellen Sie außerdem sicher, dass Sie setup-Transaktionen korrekt und ohne ordnungsgemäße tx setup-verbindungen werden nicht geschlossen, als der Frühling nicht weiß, dass es sollte in der Nähe der Verbindung.
InformationsquelleAutor M. Deinum