Frage Fehlende Verbindungen im tomcat jdbc-Verbindungspool


Wir haben gerade von dbcp zu tomcat jdbc connection pooling migriert. Wir haben das System unter Last ausprobiert und folgende Ausnahme erhalten:

java.sql.SQLException: [IA1856] Timeout: Pool empty. Unable to fetch a connection in 1 seconds, none available[size:125; busy:90; idle:0; lastwait:1000].
        at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:632)
        at org.apache.tomcat.jdbc.pool.ConnectionPool.getConnection(ConnectionPool.java:174)
        at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:124)
        at com.inneractive.model.mappings.BasicPersistenceEntityMapping.getConnection(BasicPersistenceEntityMapping.java:233)
        at com.inneractive.model.mappings.BasicPersistenceEntityMapping.callWithConnection(BasicPersistenceEntityMapping.java:243)
        at com.inneractive.model.mappings.PersistenceEntityMapping.get(PersistenceEntityMapping.java:194)
        at com.inneractive.model.data.client.ClientUtils.GetClientByExamples(ClientUtils.java:353)
        at com.inneractive.client.ExternalAdRingsClientStart.getClientInfoByRequestParametersOrInsert(ExternalAdRingsClientStart.java:1329)
        at com.inneractive.client.ExternalAdRingsClientStart.newClientSession(ExternalAdRingsClientStart.java:245)
        at com.inneractive.simpleM2M.web.SimpleM2MProtocolBean.generateCampaign(SimpleM2MProtocolBean.java:235)
        at com.inneractive.simpleM2M.web.SimpleM2MProtocolBean.generateCampaign(SimpleM2MProtocolBean.java:219)
        at com.inneractive.simpleM2M.web.AdsServlet.doGet(AdsServlet.java:175)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:555)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:396)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)

Beachten Sie Folgendes:

[size:125; busy:90; idle:0; lastwait:1000]

Wo sind die Verbindungen, die nicht beschäftigt sind? Die geschäftige Nummer ging danach nach unten, aber wir schafften es immer noch nicht, irgendwelche Verbindungen zu bekommen.

Irgendwelche Ideen?

Aufbau:

<Resource auth="Container" driverClassName="com.mysql.jdbc.Driver"
                factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" loginTimeout="10000"
                maxActive="35" maxIdle="35" maxWait="1000" name="jdbc/mysql"
                password="-----" testOnBorrow="true" testOnReturn="false" type="javax.sql.DataSource"
                url="jdbc:mysql://localhost:3306/my_db?elideSetAutoCommits=true&amp;useDynamicCharsetInfo=false&amp;rewriteBatchedStatements=true&amp;useLocalSessionState=true&amp;useLocalTransactionState=true&amp;alwaysSendSetIsolation=false&amp;cacheServerConfiguration=true&amp;noAccessToProcedureBodies=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"
                username="root" validationQuery="SELECT 1"/>

env: ubuntu und tomcat 6. db - mysql


20
2017-07-12 11:37


Ursprung


Antworten:


Werfen Sie einen Blick auf die Quelle von Verbindungspool.java Sie scheinen diesen Codeausschnitt in der borrowConnection() Methode:

        //we didn't get a connection, lets see if we timed out
        if (con == null) {
            if ((System.currentTimeMillis() - now) >= maxWait) {
                throw new SQLException("[" + Thread.currentThread().getName()+"] " +
                    "Timeout: Pool empty. Unable to fetch a connection in " + (maxWait / 1000) +
                    " seconds, none available["+busy.size()+" in use].");
            } else {
                //no timeout, lets try again
                continue;
            }
        }

Also entsprechend ist deine Verbindung Null.

Der Wert von con wird in der Zeile abgerufen:

PooledConnection con = idle.poll();

Wenn Sie den Code verfolgen, werden Sie sehen idle ist (abhängig von Ihrer Konfiguration, aber standardmäßig) FairBlockingQueue. Sie können die Implementierung für Hinweise auschecken.

Im Allgemeinen müssen Sie immer ResultSets, Statements und Connections schließen und verwendete Verbindungen sollten korrekt wieder in den Pool freigegeben werden. Wenn dies nicht korrekt geschieht, können die Verbindungen nie geschlossen werden => nie wieder zur Wiederverwendung verfügbar sein (Verbindungspool "Lecks").

Ich schlage vor, Sie erstellen eine detaillierte Protokollierung über den Zustand des Pools und überwachen sie, um das Problem zu isolieren.

Einige Richtlinien von Apache zum Verhindern von Lecks in Datenbankverbindungspools:

removeAbandoned="true"

Verlassene Datenbankverbindungen werden entfernt und wiederverwendet

removeAbandonedTimeout="60"

Legen Sie die Anzahl der Sekunden fest, die eine Datenbankverbindung im Leerlauf war, bevor sie als abgebrochen betrachtet wird

logAbandoned="true"

protokollieren Sie eine Stack-Ablaufverfolgung des Codes, der die Datenbankverbindungsressourcen verlassen hat. Beachten Sie, dass "das Protokollieren von abgebrochenen Verbindungen zusätzlichen Aufwand für jede Verbindung mit sich bringt, da ein Stack-Trace generiert werden muss."

Ich denke immer noch, dass das etwas ansteigt maxWait Wert (1200, 1500, 1700 - nur experimentieren, es gibt keinen Unterschied in den Antwortzeiten aus Benutzerperspektive) wird jene seltenen Fälle klären, in denen Sie noch Probleme haben.


16
2017-07-26 14:30



"Wo sind die Verbindungen, die nicht beschäftigt sind?"

Es klingt, als wären sie gelöscht worden und aus irgendeinem Grund versucht Ihr Verbindungspool nicht, sie erneut zu verbinden.

Fügen Sie dies der URL hinzu, mit der Sie eine Verbindung herstellen:

autoReconnect=true

Fügen Sie der Ressource als Eigenschaft eine Eigenschaft hinzu, die dazu führt, dass ungültige Verbindungen automatisch wieder hergestellt werden.

validationQuery="SELECT 1"

Außerdem sollten Sie sehen, dass Verbindungen gelöscht werden:

logAbandoned="true"

Es gibt mehrere ähnliche Fragen zum Stapelüberlauf.

Tomcat-Verbindungspooling, inaktive Verbindungen und Verbindungsherstellung JDBC-Verbindungspool wird nicht erneut geöffnet Verbindungen in tomcat

Es kann jedoch auch sein, dass Sie die Verbindungen nicht vollständig freigeben, was die Ursache für das Sterben ist. JDBC MySql-Verbindungs-Pooling-Praktiken, um einen erschöpften Verbindungspool zu vermeiden


5
2017-07-26 12:41



scheint ein Fehler im Pool zu sein, size Die Variable wird inkrementiert und versucht dann, eine Verbindung herzustellen. Aber wenn die Schöpfung scheitert ... haben wir size Wert groß und keine tatsächlichen Verbindungen im Pool - schrecklich:

    //if we get here, see if we need to create one
    //this is not 100% accurate since it doesn't use a shared
    //atomic variable - a connection can become idle while we are creating
    //a new connection
    if (size.get() < getPoolProperties().getMaxActive()) {
        //atomic duplicate check
        if (size.addAndGet(1) > getPoolProperties().getMaxActive()) {
            //if we got here, two threads passed through the first if
            size.decrementAndGet();
        } else {
            //create a connection, we're below the limit
            return createConnection(now, con, username, password);
        }
    } //end if

5
2017-10-24 12:45