org.springframework.jdbc.Unterstützung.SQLErrorCodesFactory.getErrorCodes blockiert threads

Bin ich mit einem tomcat-server mit services entwickelt, mit Feder v 4.1.0. Ich bin erstellen von jdbc-verbindungen zu einer informix-Datenbank und gelegentlich erhalten Sie eine Fehlermeldung. Diese verbindungen sind einzelne verbindungen und nicht gebündelt (wie ich es bin, den Anschluss zu dynamisch generierten Datenbank-hosts je nach unterschiedlicher input-Kriterien).

Laufe der Zeit scheint alles zu sein, voran zu fein und dann plötzlich fange ich an einen massiven Aufschwung der tomcat-threads, die weiterhin, bis ich traf meinen max-threads und alle Anfragen an den server zu bekommen, abgelehnt. Mache einen thread-dump zeigt, dass alle Fäden aufgehängt werden, auf org.springframework.jdbc.Unterstützung.SQLErrorCodesFactory.getErrorCodes.

- org.springframework.jdbc.support.SQLErrorCodesFactory.getErrorCodes(javax.sql.DataSource) @bci=56, line=204 (Interpreted frame)
- org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.setDataSource(javax.sql.DataSource) @bci=5, line=134 (Interpreted frame)
- org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.<init>(javax.sql.DataSource) @bci=6, line=97 (Interpreted frame)
- org.springframework.jdbc.support.JdbcAccessor.getExceptionTranslator() @bci=22, line=99 (Interpreted frame)
- org.springframework.jdbc.support.JdbcAccessor.afterPropertiesSet() @bci=25, line=138 (Interpreted frame)
- org.springframework.jdbc.core.JdbcTemplate.<init>(javax.sql.DataSource, boolean) @bci=50, line=182 (Interpreted frame)
- com.business.stores.data.dao.impl.BaseDAOImpl.getJdbcTemplate(int) @bci=86, line=53 (Interpreted frame)
...

Habe ich hochgezogen, die Quelle für die Frühjahr-Klasse aufgeführt ist, und es gibt einen synchronen block innerhalb es, aber ich bin nicht sicher, warum es würde andernfalls zu führen und hängen bis alle threads in dem system. (Es scheint, dass, nachdem es blockiert alle nachfolgenden SQL-Fehler wird auch blockieren, bis keine threads verfügbar auf der box. Hier ist der code vom Frühjahr in Frage:

public SQLErrorCodes getErrorCodes(DataSource dataSource) {
    Assert.notNull(dataSource, "DataSource must not be null");
    if (logger.isDebugEnabled()) {
        logger.debug("Looking up default SQLErrorCodes for DataSource [" + dataSource + "]");
    }

    synchronized (this.dataSourceCache) {
        //Let's avoid looking up database product info if we can.
        SQLErrorCodes sec = this.dataSourceCache.get(dataSource);
        if (sec != null) {
            if (logger.isDebugEnabled()) {
                logger.debug("SQLErrorCodes found in cache for DataSource [" +
                        dataSource.getClass().getName() + '@' + Integer.toHexString(dataSource.hashCode()) + "]");
            }
            return sec;
        }
        //We could not find it - got to look it up.
        try {
            String dbName = (String) JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductName");
            if (dbName != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Database product name cached for DataSource [" +
                            dataSource.getClass().getName() + '@' + Integer.toHexString(dataSource.hashCode()) +
                            "]: name is '" + dbName + "'");
                }
                sec = getErrorCodes(dbName);
                this.dataSourceCache.put(dataSource, sec);
                return sec;
            }
        }
        catch (MetaDataAccessException ex) {
            logger.warn("Error while extracting database product name - falling back to empty error codes", ex);
        }
    }

    //Fallback is to return an empty SQLErrorCodes instance.
    return new SQLErrorCodes();
}

------- UPDATE
An diesem Punkt bin ich an einem Verlust zu bestimmen, was das sperren dataSourceCache oder wie man es beheben.

Aktiviert die Protokollierung (und Debuggen) für die Frühjahr-Modul und dann gezwungen wird das Problem durch den Aufruf der service mit einer Website in einer anderen Umgebung (und daher anderes Passwort). Der Dienst kehrte das ungültige Passwort-Antwort erwartet, aber es war der diese Zeilen in der log.

Erscheint es geladen haben, die Daten korrekt:

2015-10-27 21:09:26,677||DEBUG||SQLErrorCodesFactory.getErrorCodes(175)||||SQL error codes for 'Informix Dynamic Server' found

Aber es hatte eine Art von Problem, abrufen von Daten:

2015-10-27 21:09:33,162||DEBUG||SQLErrorCodesFactory.getErrorCodes(199)||||Looking up default SQLErrorCodes for DataSource [org.springframework.jdbc.datasource.SingleConnectionDataSource@149e2931]
2015-10-27 21:09:34,254||DEBUG||SQLErrorCodesFactory.getErrorCodes(217)||||Database product name cached for DataSource [org.springframework.jdbc.datasource.SingleConnectionDataSource@50e91794]: name is 'Informix Dynamic Server'

2015-10-27 21:09:34,255||INFO ||MarkdownVoidByCashierDAOImpl.getVoidByCashierFromStore(47)||||Created JDBC Template for 68

- Und dann warfen die Fehler, die ich erwartet hatte:

2015-10-27 21:09:34,317||WARN ||SQLErrorCodesFactory.getErrorCodes(227)||||Error while extracting database product name - falling back to empty error codes
org.springframework.jdbc.support.MetaDataAccessException: Could not get Connection for extracting meta data; nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Incorrect password or user com.informix.asf.IfxASFRemoteException: user1@::ffff:10.63.112.131 is not known on the database server.
        at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:297)
        at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:324)
        at org.springframework.jdbc.support.SQLErrorCodesFactory.getErrorCodes(SQLErrorCodesFactory.java:214)
        at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.setDataSource(SQLErrorCodeSQLExceptionTranslator.java:134)
        at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.<init>(SQLErrorCodeSQLExceptionTranslator.java:97)
        at org.springframework.jdbc.support.JdbcAccessor.getExceptionTranslator(JdbcAccessor.java:99)
        at org.springframework.jdbc.support.JdbcAccessor.afterPropertiesSet(JdbcAccessor.java:138)
        at org.springframework.jdbc.core.JdbcTemplate.<init>(JdbcTemplate.java:182)
...

Natürlich, das scheint noch nicht neu das Problem (ich habe nicht wirklich erwarten, dass es, die bisherigen versuche, bei Neuerstellung der Frage gescheitert) also werde ich weiterhin verfolgen, bis das Problem erneut Auftritt.

------ UPDATE 2

Also das Problem trat wieder auf die box. Die logs anschaut mit Debuggen, ich bin nicht zu sehen, viel zu zeigen, mir gegenüber die Ursache aber.

Ich sehe das grundlegende Muster immer und immer wieder:

2015-10-27 21:28:11,178||DEBUG||SQLErrorCodesFactory.getErrorCodes(199)||||Looking up default SQLErrorCodes for DataSource [org.springframework.jdbc.datasource.SingleConnectionDataSource@3da15c49]
...
2015-10-27 21:28:13,481||DEBUG||SQLErrorCodesFactory.getErrorCodes(217)||||Database product name cached for DataSource [org.springframework.jdbc.datasource.SingleConnectionDataSource@207e4667]: name is 'Informix Dynamic Server'
2015-10-27 21:28:13,482||DEBUG||SQLErrorCodesFactory.getErrorCodes(175)||||SQL error codes for 'Informix Dynamic Server' found

Den hex-Wert am Ende der einzelnen Verbindung die Datenquelle ist das einzige, was sich ändert.

Auf einen Fehler oder zwei ich sehe die folgenden:

2015-10-27 21:27:33,622||WARN ||SQLErrorCodesFactory.getErrorCodes(227)||||Error while extracting database product name - falling back to empty error codes

Aber ich glaube, dass zeigt nur, wenn ich eine völlig ungültige server-Namen als Ziel. Es scheint, dass es geht in der synchronisierten block auf jeder SQL-nennen obwohl. Ein grep auf die log-für die Linien mit der "Suche für" vs "gefunden" zeigt über 300 Unterschied, wo lookings nicht getroffen haben einen entsprechenden gefunden. Dies wäre im Einklang mit den threads, die blockiert und kann nicht Voraus, da die Suche debug-Zeile erfolgt, die außerhalb des synchronen block.

Schalten Sie die debug-Protokollierung für diese Klasse. Ich würde auch einen Blick auf den Inhalt getErrorCodes(String).
Ich habe debugging aktiviert. Es kann eine Weile dauern, weil das Problem ist nicht zuverlässig reproduzierbar. Es wird schließlich vorkommen, kann aber eine Weile dauern. Ich werde aktualisieren mit debug-Ergebnisse, wenn ich Sie habe.
Aktualisiert mit debug-Ergebnisse
Die nur fragwürdige Sache, die sich innerhalb der synchronized block ist der Aufruf JdbcUtils.extractDatabaseMetaData. Alle anderen code ist im Grunde nur der überprüfung WeakHashMaps. Es ruft auch eine Datenbank-Verbindung mit DataSourceUtils.getConnection(DataSource). Das wäre ein Prima Kandidat für so etwas schief gehen, den Faden zu warten, für einen Connection (oder auf einige andere Aspekte) und schließlich einfrieren des Systems. Es sollte sich etwas zu, haben Sie Debuggen aktiviert org.springframework.jdbc.datasource?
Auf der Suche um schnell fand ich nur dieser, aber das schien nur der Programmierer Schuld. Allerdings ist das definitiv ein "hängen" würdiger Ort.

InformationsquelleAutor Velo | 2015-10-27

Schreibe einen Kommentar