I have a MySql Master/Slave replication question that google couldn't seem to answer. When using com.mysql.jdbc.ReplicationDriver, how does the driver handle failures on read replicas? Does it blacklist them, does it try just continue to try them and throw an exception each time (after whatever timeouts are configured)? From my testing it seems that my application is just hanging when I kill a read replica. I'm using tomcat and here is my context.xml....
<Resource auth="Container"
driverClassName="com.mysql.jdbc.ReplicationDriver"
defaultAutoCommit="false"
initialSize="10"
minIdle="5"
logAbandoned="false"
maxIdle="10"
maxWait="10000"
name="jdbc/db"
removeAbandoned="true"
testOnBorrow="true"
removeAbandonedTimeout="86400"
testWhileIdle="true"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
username="powerptc"
password="password"
url="jdbc:mysql:replication://localhost:3306,host1,host2:3306/db?allowSlavesDownConnections=true&readFromMasterWhenNoSlaves=true"
validationQuery="/* ping */ SELECT 1"
validationQueryTimeout="5" />
Is there a way to have the driver blacklist a failed read replica ( for x minutes ) instead of just retrying it over and over again?
In this case MySQL driver uses LoadBalanced driver for slaves and switch to master only if picking connection from LoadBalanced cluster of slaves fails.
Application hanging because default value for retriesAllDown = 120.
If you set retriesAllDown = 4, then Load Balancer will sleep 4 times for 250 milliseconds before switching to master.
By default loadBalanceBlacklistTimeout = 0, it means that load balancer for slaves does not use blacklist. Even if you set loadBalanceBlacklistTimeout > 0, it does not help, because strange implementation of blacklist, which is empty if all hosts are added to blacklist. But you can use next trick: Use ServerAffinityStrategy and put master hostname to slaves list, but set only slaves as affinity servers.
My working url is:
jdbc:mysql:replication://master:3306,slave1,slave2:3306/db?allowSlaveDownConnections=true&readFromMasterWhenNoSlaves=true&loadBalanceBlacklistTimeout=30000&retriesAllDown=4&loadBalanceStrategy=serverAffinity&serverAffinityOrder=slave1,slave2
In result, master will be used only if there is no available slave
Related
I experienced an outage with my application the other day and I need to understand how to avoid this in the future.
We have a Java based web application running on Tomcat 7. The application connected to several different data sources including an Oracle database.
Here are the details, the Oracle database server went down and had to be rebooted. My simple understanding tells me this would have severed the application's connections to the database, and in fact the users reported errors in the application.
The Oracle data source is setup in Tomcat's sever.xml as a GlobalNaming Resource:
<Resource name="datasource"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
....
initialSize="4"
minIdle="2"
maxIdle="8"
maxActive="8"
maxAge="28800000"
maxWait="30000"
testOnBorrow="false"
testOnReturn="false"
testWhileIdle="false"
validationQuery="SELECT 1 FROM dual"
validationQueryTimeout="10"
validationInterval="600000"
timeBetweenEvictionRunsMillis="60000"
minEvictableIdleTimeMillis="900000"
removeAbandoned="true"
removeAbandonedTimeout="60"
logAbandoned="true"
jmxEnabled="true" />
So here is what I understand regarding connection validation.
Connections are not validated while idle (testWhileIdle = false), when borrowed (testOnBorrow = false), when returned (testOnReturn = false)
The PoolSweeper is enabled because timeBetweenEvictionRunsMillis > 0, removeAbandoned is true, and removeAbandonedTimeout > 0
What confuses me is the inclusion of the validation query and the validationInterval > 0. Since all of the tests are disabled, does the pool sweeper then use the validation query to check the connections? Or is the validation query irrelevant?
So when the database server went down, I believe the connection pool would not have tried to reestablish connections because there are no validation tests enabled. In my opinion, had testOnBorrow been enabled then when the database server came back up valid connections would have been established and the web application (meaning tomcat) would not have required a restart.
Do I have a correct understanding of how connection validation works?
Let us take a look at the relevant part of your configuration to avoid invalid connections in your pool.
maxAge="28800000"
The connections regardless if valid or not will be kept open for 8 hrs. After 8 hrs the connection is closed and a new connection will be established if requested and no free connection is available in the pool. [1]
testOnBorrow="false"
testOnReturn="false"
testWhileIdle="false"
A connection in the pool will not be tested if it is valid when or while it's been borrowed, returned and idle. [1]
validationInterval="600000"
This property has no effect since all connection tests are set to false. This interval defines when a connection is needed to be tested. In your example, a connection will be tested every 10 minutes in case a test property would be set to true. [1]
An invalid connection can stay open up to 8 hrs with your current configuration. To enable validation tests of opened connections you have to set at least one test property (testOnBorrow, testOnReturn, testWhileIdle) to true.
Please note, in case of validationInterval="600000" a connection test/validation will be done every 10 minutes. So, an invalid connection could be up to 10 minutes available in the pool regardless which test property is set.
For more information about the individual properties please take a look at [1]: Apache Tomcat 7: The Tomcat JDBC Connection Pool.
you must lower the maxAge="28800000" parameter, in addition to this your instance crashes due to application errors and you should use jdbc interceptor
I have a mysql database configured with a max_connections value of 150. I also have a Java 6 web application running in Tomcat 5.5 configured with the following setup:
<Resource name="jdbc/myDB"
type="javax.sql.DataSource"
driver="com.mysql.jdbc.Driver"
username="username"
password="password"
maxActive="100"
maxIdle="100"
maxWait="-1"
removeAbandoned="true"
removeAbandonedTimeout="300"
logAbandoned="true"
url="jdbc:mysql://localhost:3306/myDB?autoreconnect=true"
validationQuery="SELECT 1" />
This application is not using any 3rd party framework just basic java servlets. I have a bug in some code in the java app that is not properly releasing opened mysql connections from the pool. I am working on identifying and fixing these. But in the meantime I need to figure out why at most there is only 25 connections being allowed to mysql. After these 25 connections are used up, the application becomes unresponsive.
Can someone please help me figure out why both mysql and tomcat are configured for 100+ connections but it is only allowing 25 at a time?
Tomcat JDBC Connection Pool
What connection pool do you use?
Do you use the Tomcat JDBC Connection Pool, rather than the Apache Commons pool? It has properties to detect connection leaks or abandon connection that are open for a long time than the configured timeout.
MySQL's max_connections was set to 150 but the max_user_connections was set to 25 which was the limiting factor here. I removed this setting from my.cnf to restore it to the default value of unlimited.
Here is my current config
<Resource
name="jdbc/data"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/TABLE_NAME"
username="USER_NAME"
password="PASSWORD"
initialSize="10"
maxActive="50"
suspectTimeout="120"
minIdle="10"
maxIdle="20"
maxWait="1000"
testOnBorrow="true"
timeBetweenEvictionRunsMillis="30000"
minEvictableIdleTimeMillis="60000"
validationQuery="SELECT 1 FROM DUAL"
validationInterval="40"
removeAbandoned="true"
removeAbandonedTimeout="100"
/>
This is in global context so multiple apps can use it.
I am little confused about parameters.need some details.
What I understand is
initalSize a number of connection created when a pool started.
maxActive maximum 50 connections can active at a time.
minIdle 10 connections remain Idle when connection is not used else are closed after maxwait
maxIdle 20 connections can be store as idle.
But When I start tomcat server I can see a 30 IDLE connections which remains forever.Why this happens? Am I missing something ? According to my understanding about connection pool there should only 10 connections should created and can stay in IDLE mode. Is there any specific changes that I have to do with mysql my.cnf
When you say...
This is in global context so multiple apps can use it.
What specifically do you mean? Is it in $CATALINA_BASE/conf/server.xml in the GlobalNamingResources block or in $CATALINA_BASE/conf/context.xml?
Defining a Resource tag in the GlobalNamingResources block of $CATALINA_BASE/conf/server.xml will cause only one resource to be created across the entire server. This can then be shared to applications deployed on your system by adding a ResourceLink tag to the Context configuration.
Defining a Resource in $CATALINA_BASE/conf/context.xml will define the resource once for each application deployed to your Tomcat instance. Thus if you have three applications deployed, you'll end up with three separate resources. This is a guess, but probably why you are seeing 30 connections to your database server.
I have a web-app with a Java back-end that uses Tomcat jdbc-pool for database connections. This works fine.
However I am trying to foolproof it before exporting it to other locations, and recently a scenario occurred where someone restarted the SQL Server database service but did not restart the Tomcat service. This caused a SQLException: java.sql.SQLException: I/O Error: Connection reset by peer: socket write error until I restarted Tomcat, forcing the jdbc-pool datasource to reconnect.
I looked for some kind of a configuration in the Tomcat jdbc-pool docs to tell the datasource to attempt to reconnect but I couldn't find anything.
Does anyone know if there is some kind of configuration for this or should I check this condition before each request?
Not 100% sure if this is your problem but on http://www.tomcatexpert.com/blog/2010/04/01/configuring-jdbc-pool-high-concurrency it says you can use testOnBorrow with a validationQuery.
<Resource type="javax.sql.DataSource"
...
testOnBorrow="true"
validationQuery="SELECT 1"
removeAbandoned="true"
/>
While checking for the same issue I came across this post which has the auto connect configurations for all app servers.
Below are the configuration which I used for auto connect in tomcat for reference.
<Resource auth="Container"
driverClassName="oracle.jdbc.OracleDriver"
initialSize="5"
maxActive="120"
maxIdle="5"
maxWait="5000"
name="jdbc/oracle/myds"
password="secret"
poolPreparedStatements="true"
type="javax.sql.DataSource"
url="jdbc:oracle:thin:#DBHOSTNAME:1521/ServiceName"
username="testuser"
validationQuery="select 1 from tab"
testOnBorrow="true"/>
Complete auto connect configurations for all app servers can be found here in Datasource autoreconnect in Java Application Servers.
Just to add on to Natan Cox's answer
Reference - http://tomcat.apache.org/tomcat-8.0-doc/jdbc-pool.html#Common_Attributes
<Resource type="javax.sql.DataSource"
...
testOnBorrow="true"
validationQuery="SELECT 1"
removeAbandoned="true"
/>
As against Geronimo, I would still like to use validationQuery
Database validationQuery notes
hsqldb - select 1 from INFORMATION_SCHEMA.SYSTEM_USERS
Oracle - select 1 from dual
DB2 - select 1 from sysibm.sysdummy1
mysql - select 1
microsoft SQL Server - select 1
postgresql - select 1
ingres - select 1
derby - values 1
H2 - select 1
Firebird - select 1 from rdb$database
Reference - DBCP - validationQuery for different Databases
<Resource name="myConn" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:#10.10.10.10.:1521:mydb"
username="username" password="password" maxActive="500" maxIdle="50"
maxWait="-1" removeAbandoned="true" removeAbandonedTimeout="60" logAbandoned="true" accessToUnderlyingConnectionAllowed="true"
/>
I am trying to find out areas of the application where connections are NOT being closed. I added the removeAbandoned and logAbandoned clauses in my context file but if i check v$session on oracle it is still showing the same number of connections active even after 60 seconds. Is there something wrong in the configuration above?
I would set maxActive to smaller value like 50 and then check if the configuration is working correctly.
According to the docs the connections pool must running low to execute the check for abandoned connections:
When available db connections run low
DBCP will recover and recycle any
abandoned dB connections it finds.
I would also changed the removeAbandonedTimeout to 20 so that you won't have to wait to long to check if the detector is working fine.