L'analyse de fermeture de la Connexion Exception dans Spring/JPA/Mysql/Tomcat app

PROBLÈME

Récemment, j'ai été chargé d'une application web Java avec le code déjà écrit et en place. L'application reçoit moyennement élevés de trafic et a des heures de pointe de trafic entre 11h à 3h tous les jours.
L'application utilise Spring, JPA(Hibernate), de bases de données MYSQL.
Le printemps a été configuré pour utiliser tomcat pool de connexions jdbc pour établir des connexions à la bd.
(Les détails de la configuration à la fin du post)

Depuis quelques jours, lors de l'application de la charge de pointe heures, la demande a été de descendre en raison de tomcat va de répondre aux demandes. Il est nécessaire de tomcat être redémarré plusieurs fois.

En passant par le tomcat catalina.rondins, j'ai remarqué un tas de

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

Elles apparaissent souvent juste avant le crash.

Aller plus loin, plus avant ces exceptions près, j'ai remarqué un tas de Connexions être abandonné juste avant la fermeture de la Connexion des exceptions.

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)

Ces semblent souvent juste avant la fermeture de la Connexion des exceptions. Et ceux-ci semblent être les premiers symptômes d'une catastrophe imminente dans les journaux.

ANALYSE

En passant par les journaux, j'ai décidé de voir si il n'y a aucun pool de connexion de configuration/configuration de mysql qui pourraient être à l'origine du problème.
Est passé par un couple d'excellents articles qui montrent le réglage de la piscine pour un environnement de Production. Liens Un & Deux

Passant par ces articles, j'ai remarqué que:

  1. La ligne ci-dessous dans JHanik l'article (lien 1) mentionne cette

    Réglage de la valeur de abandonWhenPercentageFull à 100 signifie que les connexions ne sont pas > considérée comme abandonnée si nous avons atteint notre maxActive limite.

    J'ai pensé que cela pourrait être important dans mon cas, parce que je vois beaucoup de connexions être abandonné.

  2. Mon max_connections configuration ne correspond pas à ce qui est recommandé (lien 2)

    mysql max_connections doit être égale à max_active+max_idle

CE QUE J'AI ESSAYÉ

Donc, conformément aux recommandations de l'article, j'ai fait deux choses:

  1. Changé abandonWhenPercentageFull à 100
  2. Dans mon serveur MYSQL, max_connections avait été fixé à 500. Il a augmenté à 600
    Dans mes paramètres du pool de connexions, max_active était de 200 et max_idle était de 50.
    Changé max_active=350, max_idle = 250

CELA N'AIDE PAS

Le lendemain, les observations suivantes ont été faites pendant les heures de pointe:

  1. Tomcat de ne pas descendre. L'app est resté sur place à travers des heures de pointe.
    Cependant, la performance est allé de mal en pis et puis l'application a été à peine utilisable, même si elle n'a pas vraiment aller vers le bas.
  2. DB pool de Connexion, mais ont augmenté en taille, a été totalement utilisé, et j'ai pu voir à 350 connexions actives à la DB à un point.

ENFIN, MA QUESTION:

Clairement ressemble, il y a des problèmes avec la façon DB connexions sont réalisées à partir de l'application serveur.
J'ai donc deux orientations à prendre cette analyse de l'avant.

Ma question est de savoir lequel de ces dois-je prendre?

1. Le problème n'est pas avec les paramètres du pool de connexions. Le code est ce qui est à l'origine du problème

Il pourrait y avoir des endroits dans le code où DB connections ne sont pas fermés. Qui est à l'origine du nombre élevé de connexions ouvertes.

Le code utilise une GenericDao qui se prolonge dans chaque classe Dao. Le GenericDao utilise du Printemps JpaTemplate pour aller chercher un EntityManager instance, qui à son tour est utilisé pour tous les DB opérations. Ma compréhension est à l'aide de la JpaTemplate gère le nitty gritty de clôture DB connexions à l'interne.

Alors, où, exactement, dois-je recherche de la possibilité de connexion à des fuites?

2. Le problème est avec le pool de connexions/mysql config paramètres. Cependant, les optimisations que j'ai mis dans la nécessité d'être à l'écoute de plus amples

Si oui, quels paramètres dois-je regarder?
Devrais-je être à la collecte de certaines données à utiliser pour déterminer les valeurs appropriées pour mon pool de connexion. (Pour exemple, pour max_active, max_idle, max_connections)


Addendum: Compléter le Pool de Connexion de configuration

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

OriginalL'auteur ncmadhan | 2014-02-11