Why does my Tomcat only open 8 JDBC connections

4.6k views Asked by At

When setting up the database connections in Tomcat 8, for some reason Tomcat is not following what I configured in the context.xml, with as result that I run out of connections, leading to resource contentions at the application server side (BLOCKED/WAITING threads). I always have 8 connections (show processlist in mariadb/mysql) after the pool initializes. My configuration states a minimum of 10 connections and a maximum of 100 connections.

I tested different configurations, but this does not make any difference at all, which is strange at least. The context.xml is used else it would not be able to connect to the database at all.

What is happening here? Why only 8 connections?

Software versions: - MySQL JDBC driver: Latest (5.1.35) - Java 1.8.0_05

I also observed with with my previous setup: Tomcat 7, Java 1.7, older MySQL JDBC drivers, MySQL instead of MariaDB. So the problem does not seem directly version related.

Show processlist output (Showing the 8 processes):

| Id    | User          | Host          | db                | Command | Time | State     | Info            | Progress |                                                                     
+-------+---------------+---------------+-------------------+---------+------+-----------+-----------------+----------+
| 71153 | root          | localhost     | vnitdatacollector | Query   |    0 | init      | show processlist|    0.000 |                                                                     
| 73473 | vnit_datacoll | virt005:58585 | vnitdatacollector | Sleep   |    0 |           | NULL            |    0.000 |                                                                     
| 73474 | vnit_datacoll | virt005:58586 | vnitdatacollector | Sleep   |    0 |           | NULL            |    0.000 |                                                                     
| 73482 | vnit_datacoll | virt005:58606 | vnitdatacollector | Query   |    0 | update    | INSERT INTO ... |    0.000 |
| 73483 | vnit_datacoll | virt005:58607 | vnitdatacollector | Sleep   |    0 |           | NULL            |    0.000 |                                                                     
| 73485 | vnit_datacoll | virt005:58618 | vnitdatacollector | Query   |    0 | query end | INSERT INTO ... |    0.000 |
| 73487 | vnit_datacoll | virt005:58624 | vnitdatacollector | Sleep   |    0 |           | NULL            |    0.000 |                                                                     
| 73488 | vnit_datacoll | virt005:58634 | vnitdatacollector | Sleep   |    0 |           | NULL            |    0.000 |                                                                     
| 73489 | vnit_datacoll | virt005:58637 | vnitdatacollector | Query   |    7 | update    | INSERT INTO ... |    0.000 |
+-------+---------------+---------------+-------------------+---------+------+-----------+-----------------+----------+

I have the following context.xml configuration:

<?xml version="1.0" encoding="UTF-8"?>
<Context>
  <Resource 
    name="jdbc/dbaccess" 
    auth="Container" 
    type="javax.sql.DataSource"
    maxActive="100" 
    maxIdle="100"
    minIdle="10"
    maxWait="1000"
    initialSize="10"
    minEvictableIdleTimeMillis="5000"
    testOnBorrow="true"
    validationQuery="SELECT 1" 
    timeBetweenEvictionRunsMillis="5000" 
    testWhileIdle="true"
    removeAbandoned="true" 
    removeAbandonedTimeout="60" 
    logAbandoned="true"
    username="some_user" 
    password="{the password}" 
    driverClassName="com.mysql.jdbc.Driver"
    url="jdbc:mysql://dbserver:3306/dbaccess?useFastDateParsing=false&amp;jdbcCompliantTruncation=false"
  />
  <Resource
    name="mail/emailconnection"
    auth="Container"
    type="javax.mail.Session"
    mail.smtp.host="some.stmp.server"
  />             
</Context>

The following thread issue then shows up after a (short) period:

"Thread-495" #517 daemon prio=5 os_prio=0 tid=0x00007f678c040800 nid=0x1642 waiting on condition [0x00007f67848f4000]
java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000f21933f0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
    at org.apache.tomcat.dbcp.pool2.impl.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:582)
    at org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:439)
    at org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:360)
    at org.apache.tomcat.dbcp.dbcp2.PoolingDataSource.getConnection(PoolingDataSource.java:118)
    at org.apache.tomcat.dbcp.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:1412)
    at com.hipersonik.util.ServiceLocator.getConnection(ServiceLocator.java:32)
2

There are 2 answers

1
Norbert On BEST ANSWER

Quote from "Tomcat Expert: Configuring jdbc-pool for high-concurrency":

When Tomcat reads the type="javax.sql.DataSource" it will automatically configure its repackaged DBCP, unless you specify a different factory. The factory object is what creates and configures the connection pool itself.

It turns out that DBCP package just ignores a series of settings. Adding the following line to the context.xml resource configuration, gets better response in the database:

<Resource 
 ....
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
 ....
/>

Show processlist in mysql then immediately shows the desired behaviour.

1
jonenst On

By default (ie if not setting the factory setting of your ressource), tomcat7 uses commons dbcp1.

Tomcat also provides an alternate pool implementation (the tomcat jdbc connection pool) that you can use by setting factory=org.apache.tomcat.jdbc.pool.DataSourceFactory on your ressource

Tomcat8 uses commons dbcp2 by default, which has different names for some very important configuration parameters ( see https://tomcat.apache.org/migration-8.html#Database_Connection_Pooling ) as dbcp1 (and the tomcat jdbc connection pool, because it mostly has the same configuration options as commons dbcp1).

So basically, before tomcat8, you didn't have to pay attention to which connection pool you were using because of the configuration compatibilty. With tomcat8, you have to pay attention.

Tomcat connection pool documentation: https://tomcat.apache.org/tomcat-8.0-doc/jdbc-pool.html

Default commons dbcp2 documentation: https://tomcat.apache.org/tomcat-8.0-doc/jndi-resources-howto.html#JDBC_Data_Sources