У нас есть приложение на основе Spring и недавно мы вступили в производство. Мы используем Spring @Controller
, который в конечном итоге попадает в DAO, которые используют JDBCTemplate. Используется c3p0 ComboPooledDataSource
c3p0 DataSource monitor deadlock - все темы зависают - как исправить
При увеличенной нагрузке (что-то вроде 150 одновременных пользователей) приложение зависает для всех пользователей - DataSource блокируется чем-то - на дампе потока есть примерно 200 потоков, которые, DataSource зашел в тупик.
"http-bio-8080-exec-440" - Thread [email protected]
java.lang.Thread.State: WAITING
at java.lang.Object.wait(Native Method)
- waiting on <146d984e> (a com.mchange.v2.resourcepool.BasicResourcePool)
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1418)
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:606)
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:526)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:756)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:683)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140)
at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:573)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:637)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:666)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:674)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:718)
После этого момента приложение становится непригодным для использования, если оно не перезапущено. Когда это произошло, команда DBA не наблюдала никакой нагрузки на базу данных.
В то время C3P0 был настроен так:
После этого я изменил конфигурацию C3P0 как следует - и включена регистрация DEBUG для com.mchange.v2.c3p0
пакета:
app_en.driverClass=com.mysql.jdbc.Driver
app_en.user=tapp_en
app_en.password=tapp_en
app_en.jdbcUrl=jdbc:mysql://10.10.0.102:3306/tapp_en? useUnicode=true&characterEncoding=utf-8&autoReconnect=true
app_en.acquireIncrement=5
app_en.maxIdleTime=180
app_en.maxIdleTimeExcessConnections=60
app_en.unreturnedConnectionTimeout=30
app_en.checkoutTimeout=10000
app_en.numHelperThreads=12
app_en.debugUnreturnedConnectionStackTraces=true
app_en.initialPoolSize=10
app_en.maxPoolSize=100
app_en.idleConnectionTestPeriod=120
app_en.preferredTestQuery="select 1 from tbl_users"
С этой конфигурацией , Я снова запускал тесты нагрузки, и приложение все еще зависало ... хотя потоки восстанавливаются после того, как они не могут получить соединение с базой данных. Несмотря на то, что игра висела для слишком большого количества пользователей, хотя потоки восстановились в отличие от предыдущей конфигурации - поэтому им пришлось перезапустить свои клиенты. Хотя все записи были включены, журналы c3p0 не регистрируют никаких сообщений о блокировке. Сообщения об ошибках, которые я вижу только, что:
[06/24/2015 12:20:54] [C3P0PooledConnectionPoolManager[identityToken->1oed6dl9a9ak8qsgqfvdu|4d6145af]-HelperThread-#10] DEBUG NewPooledConnection - [email protected] closed by a client.
java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:659)
at com.mchange.v2.c3p0.impl.NewPooledConnection.closeMaybeCheckedOut(NewPooledConnection.java:255)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.destroyResource(C3P0PooledConnectionPool.java:621)
at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.java:1024)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696)
Там нет никаких сделок в подаче заявления, ни мы с помощью любого TransactionManager или TransactionTemplate. Интересно, может ли это быть какой-то ошибкой в используемых фреймах или неправильной конфигурации. Это соответствующие структуры, используемые:
c3p0-0.9.5-pre8
mysql-connector-java-5.1.24
spring-core-3.2.1.RELEASE
spring-web-3.2.1.RELEASE
mchange-commons-java-0.2.7
Мы действительно ценим любую помощь, потому что это блокирует наши усилия, чтобы выпустить наш продукт.
P.S. EDIT: Вот конфигурация DataSource:
<bean id="app_en_DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${app_en.driverClass}" />
<property name="jdbcUrl" value="${app_en.jdbcUrl}" />
<property name="user" value="${app_en.user}" />
<property name="password" value="${app_en.password}" />
<property name="acquireIncrement" value="${app_en.acquireIncrement}"></property>
<property name="maxIdleTime" value="${app_en.maxIdleTime}"></property>
<property name="maxIdleTimeExcessConnections" value="${app_en.maxIdleTimeExcessConnections}"></property>
<property name="unreturnedConnectionTimeout" value="${app_en.unreturnedConnectionTimeout}"></property>
<property name="checkoutTimeout" value="${app_en.checkoutTimeout}"></property>
<property name="numHelperThreads" value="${app_en.numHelperThreads}"></property>
<property name="debugUnreturnedConnectionStackTraces" value="${app_en.debugUnreturnedConnectionStackTraces}"></property>
<property name="initialPoolSize" value="${app_en.initialPoolSize}"></property>
<property name="maxPoolSize" value="${app_en.maxPoolSize}"></property>
<property name="idleConnectionTestPeriod" value="${app_en.idleConnectionTestPeriod}"></property>
<property name="preferredTestQuery" value="${app_en.preferredTestQuery}"></property>
</bean>
А вот какой-то код внутри приложения, не используя JdbcTemplate непосредственно. Там нет ничего, что делает это, все остальное jdbcTemplate.update, jdbcTemplate.query:
Connection conn = null;
ResultSet getItemsRS = null;
try {
JdbcTemplate jdbcTemplate = getJdbcTemplate(database);
conn = jdbcTemplate.getDataSource().getConnection();
UserItems items;
if (!action.areItemsNew()) {
conn.setAutoCommit(false);
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
PreparedStatement getItemsPS = conn.prepareStatement("select * from tbl_items where ownerId = ? for update",
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
getItemsPS.setLong(1, userId);
getItemsRS = getItemsPS.executeQuery();
getItemsRS.next();
items = new UserItemsRowMapper().mapRow(getItemsRS, getItemsRS.getRow());
} else {
items = new UserItems();
}
action.doUserItemsAction(items);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(items.getItemContainers());
oos.close();
byte[] data = baos.toByteArray();
Blob blob = conn.createBlob();
blob.setBytes(1, data);
if (!action.areItemsNew()) {
getItemsRS.updateBlob("data", blob);
getItemsRS.updateRow();
} else {
jdbcTemplate.update("insert into tbl_items(ownerId,data) values(?,?)", userId, data);
}
} catch (Exception e) {
logger.error(e);
throw new RuntimeException(e);
} finally {
if (!action.areItemsNew()) {
try {
conn.commit();
conn.close();
} catch (SQLException e) {
logger.error(e);
throw new RuntimeException(e);
}
}
}
Причиной этого кода является то, что я хотел бы, чтобы блокировать чтение/запись к элементам пользователя, прежде чем они будут обновлены эта операция action.doUserItemsAction(items)
как написано выше.
фотографии эти ссылки http://stackoverflow.com/questions/17272141/websphere-hangs-due-to-c3p0 http://stackoverflow.com/questions/14105932/c3p0-hangs-in-awaitavailable-with -hibernate http://stackoverflow.com/questions/19313103/c3p0-hangs-java-1-6 –
извините, но эти ссылки не дают мне более глубокого понимания проблемы, которую у меня уже есть ... –
Где кода и конфигурации? Также я бы предложил использовать другой пул, а не C3P0, что-то вроде [HikariCP] (https://github.com/brettwooldridge/HikariCP). –