幾個月來,我的web應用程序運行平穩,但在過去的一兩週內,它一直在斷開與MySQL服務器的連接。我不是DBA的人,也不知道如何調試。MySQL/Hibernate - 我如何調試一直不斷下降的MySQL池連接?
這是我所知道的:
- 連接似乎每隔幾個小時下降。有時在白天,但總是在夜間。
- 我的實驗室有一臺MySQL服務器,它託管多個應用程序的數據庫。
- 目前,我們有46個連接到MySQL服務器。
- 據我所知,沒有其他應用程序遇到此問題。
- 我的應用程序使用同一個堆棧,配置,甚至代碼連接到數據庫的其他應用程序,該應用程序的其他支持每天大約有200個用戶,2013年以來
已順利運行這兩個應用程序中使用Hibernate ORM;這是唯一的配置,我知道:
<!-- TomcatJDBCConnectionProvider class is common to both applications --> <property name="hibernate.connection.provider_class">org.hibernate.connection.TomcatJDBCConnectionProvider</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.pool_size">5</property> <property name="hibernate.current_session_context_class">thread</property> <property name="hibernate.tomcatJdbcPool.validationQuery">SELECT 1</property> <property name="hibernate.tomcatJdbcPool.testOnBorrow">true</property> <property name="hibernate.enable_lazy_load_no_trans">true</property>
問題開始大約在同一時間,當有人試圖使用該應用程序的REST API下載我們的數據。這個用戶 - 實際上是一個協作者 - 有一個小腳本迭代特定表中的每一行並請求所有元數據。
- 這個問題也出現在我的實驗室開始提供Coursera Massive Open Online Course的同時。我不知道這些數字是什麼,但網站上的實際使用量一定會增加。
我知道這是一個廣泛的問題,但我真的很在意如何去調試這個問題。任何建議表示讚賞。
編輯:
周圍的其他應用程序的ServletContextListener
挖掘,我發現這段代碼,我contextDestroyed
功能沒有:
// TODO: Find memory leak that requires server to be restarted after hot deploying several (3?) times.
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread t : threadSet) {
if (t.getName().contains("Abandoned connection cleanup thread")) {
synchronized (t) {
System.out.println("Forcibly stopping thread to avoid memory leak: " + t.getName());
t.stop(); // don't complain, it works
}
}
}
這似乎遍歷堆棧跟蹤,找到帶文字"Abandoned connection cleanup thread"
的手動停止。這似乎可能與我的問題有關?
編輯21/9/2015:
我的應用程序在本週末去了。下面是從昨天的錯誤日誌中的堆棧跟蹤(當我相信它去了):
20-Sep-2015 14:22:18.160 SEVERE [http-apr-8080-exec-35] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [edu.mssm.pharm.maayanlab.Harmonizome.api.GeneMetadataApi] in context with path [/Harmonizome] threw exception
org.hibernate.exception.GenericJDBCException: Could not open connection
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:304)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:169)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:67)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:160)
at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1395)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:224)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:545)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:124)
at org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:180)
at edu.mssm.pharm.maayanlab.Harmonizome.json.serdes.GeneMetadataSerializer.serialize(GeneMetadataSerializer.java:54)
at edu.mssm.pharm.maayanlab.Harmonizome.json.serdes.GeneMetadataSerializer.serialize(GeneMetadataSerializer.java:23)
at com.google.gson.TreeTypeAdapter.write(TreeTypeAdapter.java:70)
at com.google.gson.Gson.toJson(Gson.java:600)
at com.google.gson.Gson.toJson(Gson.java:579)
at com.google.gson.Gson.toJson(Gson.java:534)
at edu.mssm.pharm.maayanlab.Harmonizome.api.GeneMetadataApi.doGet(GeneMetadataApi.java:65)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
at org.apache.tomcat.util.net.AprEndpoint$SocketWithOptionsProcessor.run(AprEndpoint.java:2440)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.tomcat.jdbc.pool.PoolExhaustedException: [http-apr-8080-exec-35] Timeout: Pool empty. Unable to fetch a connection in 30 seconds, none available[size:5; busy:5; idle:0; lastwait:30000].
at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:672)
at org.apache.tomcat.jdbc.pool.ConnectionPool.getConnection(ConnectionPool.java:186)
at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:127)
at org.hibernate.connection.TomcatJDBCConnectionProvider.getConnection(TomcatJDBCConnectionProvider.java:208)
at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:292)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:297)
這裏是我的連接變量從MySQL:
mysql> SHOW VARIABLES LIKE '%connect%';
+-----------------------------------------------+-----------------+
| Variable_name | Value |
+-----------------------------------------------+-----------------+
| character_set_connection | utf8 |
| collation_connection | utf8_general_ci |
| connect_timeout | 5 |
| default_master_connection | |
| extra_max_connections | 1 |
| init_connect | |
| max_connect_errors | 100 |
| max_connections | 100 |
| max_user_connections | 0 |
| performance_schema_session_connect_attrs_size | 512 |
+-----------------------------------------------+-----------------+
mysql> SHOW VARIABLES LIKE '%timeout%';
+-----------------------------+----------+
| Variable_name | Value |
+-----------------------------+----------+
| connect_timeout | 5 |
| deadlock_timeout_long | 50000000 |
| deadlock_timeout_short | 10000 |
| delayed_insert_timeout | 300 |
| innodb_flush_log_at_timeout | 1 |
| innodb_lock_wait_timeout | 50 |
| innodb_rollback_on_timeout | OFF |
| interactive_timeout | 28800 |
| lock_wait_timeout | 31536000 |
| net_read_timeout | 30 |
| net_write_timeout | 60 |
| slave_net_timeout | 3600 |
| thread_pool_idle_timeout | 60 |
| wait_timeout | 28800 |
+-----------------------------+----------+
編輯22/9/2015 :
將一個SEVERE
Tomcat錯誤導致該問題?我看到一個錯誤,無關的數據庫中,有關分析日期:
22-Sep-2015 10:09:53.481 SEVERE [http-apr-8080-exec-26] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [edu.mssm.pharm.maayanlab.Harmonizome.page.DatasetPage] in context with path [/Harmonizome] threw exception [javax.servlet.ServletException: javax.servlet.jsp.JspException: In <parseDate>, a parse locale can not be established] with root cause
javax.servlet.jsp.JspException: In <parseDate>, a parse locale can not be established
at org.apache.taglibs.standard.tag.common.fmt.ParseDateSupport.doEndTag(ParseDateSupport.java:147)
附加堆內存使用量的JConsole的輸出:
JConsole的輸出線程的使用;它開始大約24-25,一旦我開始使用該網站,跳到34。即使在關閉瀏覽器窗口後,它仍然存在:
編輯23/9/2015:
有一件事我改變權面前的問題開始了我如何處理Hibernate事務。以前,我禁用了(這是默認設置)。以前,我使用的是「open session in view」模式。好像人們不喜歡視圖模式下的公開會話,所以我啓用了。因此,我有這樣的代碼:
List<MyObjects> myObjects = null;
try {
HibernateUtil.beginTransaction();
myObjects = // fetch my objects from the DB
HibernateUtil.commitTransaction();
} catch (HibernateException he) {
HibernateUtil.rollbackTransaction();
} finally {
HibernateUtil.close();
}
// render myObjects in JSP/JSTL
// this JSP may lazily load related objects
回想起來,這似乎...有問題。我不知道Hibernate何時「放開」對象。
內存問題?任何其他應用程序部署在Mysql和Application部署的機器上? – Gaurav
我對這個連接池實現沒有經驗,但我會開始調試實現QueryTimeoutInterceptor:https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html#org.apache.tomcat。 jdbc.pool.interceptor.QueryTimeoutInterceptor – a1ex07
@Gaurav,其他一些小應用程序在同一臺機器上運行。我們有一個集羣,出於歷史原因,我每次都在同一臺計算機上運行應用程序,但我已經重新部署,因此它可以在任何地方運行,以防一臺計算機出現問題。 – gwg