EAP 6/7 JDBC datasource not fault tolerant in JBoss and needs connection validation enabled
Environment
- Red Hat JBoss Enterprise Application Platform (EAP)
- 6
- 7
- Red Hat Single Sign On(RHSSO)
- 7.x
Issue
- How do I enable connection validation for a datasource connection pool?
- After performing database restart for maintenance or an outage is unable to reconnect to the database.
- Is a restart required to re-establish database connections after a service interruption?
- How can we gracefully handle database server initiated timeout of connections?
- Getting stale connections from the datasource pool.
- Is a "flush" of the pool required to create fresh connections?
- Is there a mechanism to test connections to ensure they are valid before use?
- How do
background-validation
andvalidate-on-match
differ? - Do we need
SELECT 1
if we have thevalid-connection-checker
configured? - What is the role of the
exception-sorter
class in the connection validation process? - Is it necessary to specify a
stale-connection-checker
and anexception-sorter
? -
Seeing
Connection is closed
errors in our server.log:ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http-/:8443-8) Closed Connection ERROR [controller.SearchController] (http-/:8443-8) javax.persistence.PersistenceException org.hibernate.exception.GenericJDBCException: Closed Connection
-
Evidence in the logs of failed Oracle connections
java.lang.RuntimeException: No more data to read from socket at oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1157) at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:290) at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192) at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531) at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:207) at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:884) at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1167) at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1289) at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3584) at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3628) at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1493) at org.jboss.jca.adapters.jdbc.CachedPreparedStatement.executeQuery(CachedPreparedStatement.java:107) at org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.executeQuery(WrappedPreparedStatement.java:462)
-
Seeing the following error when using MySQL:
... com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 59,828,176 milliseconds ago. The last packet sent successfully to the server was 59,828,176 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
Resolution
Overview
Fault tolerance/validation should be configured for every production datasource. Without this configuration, JBoss will be unable to detect externally terminated connections (i.e. terminated due to database server initiated timeout, network timeout, network interruption, etc.). Without the ability to detect stale/invalid connections, they cannot be evicted from the pool and will be provided (repeatedly) to application components which request connections. This will result in exceptions in the application layer each time these invalid/failed connections are used.
An appropriate fault tolerance/validation configuration will usually consist of the following:
<validation>
<!-- 1. The below is the recommended alternative to check-valid-connection-sql for JDBC 4+ compliant drivers.
DO NOT USE BOTH valid-connection-checker AND check-valid-connection-sql. -->
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.novendor.JDBC4ValidConnectionChecker"/>
<!-- 2. Match time validation is recommended in **most** cases, instead of background validation.
DO NOT USE BOTH validate-on-match AND background-validation. -->
<validate-on-match>true</validate-on-match>
<!-- If enabling background validation, **disable** validate-on-match and add background-validation-millis. -->
<background-validation>false</background-validation>
<!-- 3. The below is required to facilitate pool flush strategy handling -->
<exception-sorter class-name="database_specific_ExceptionSorter_here"/>
</validation>
See below for in-depth discussion and references with examples for specific datasource types.
Discussion
For datasource specific examples demonstrating recommended validation configuration, consult the database connection validation documentation specific to your EAP version:
Detailed information regarding the configuration options can be found below if the recommended configuration is not suitable for a specific system/use case.
-
NOTE : that fault tolerance/validation configuration only impacts connections which are not held/reserved by application components.
-
To be able to recover from database maintenance or an outage situation, the use of connection validation (both a timing:
validate-on-match
orbackground-validation
, and a mechanism:valid-connection-checker
orcheck-valid-connection-sql
) and the setting ofexception-sorter
are recommended when defining a datasource. -
You must complete EACH of the following 3 steps to correctly configure the datasource validation
1) Select ONE of the following validation mechanisms:
-
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.novendor.JDBC4ValidConnectionChecker" />
- This is the preferred mechanism (instead of
check-valid-connection-sql
) as the validation classes may include driver/RDBMS-specific optimizations 1. - org.jboss.jca.adapters.jdbc.extensions.novendor.JDBC4ValidConnectionChecker
- This is the recommended class for JDBC 4+ compliant drivers (even where vendor specific validation classes may also exist).
- Implementation of the
Connection.isValid(int)
method (by driver vendors) is mandatory for JDBC 4 compliance. - Only if problems in the implementation of the method are verified for the specific driver to be used should the vendor specific classes below be considered.
- Implementation of the
- WARNING Other validation mechanisms (below) may be subject to long delays due to JDBC driver blocking while accessing stale connections. Consequently, a JVM may not recover for several minutes (or longer) following any loss of connectivity.
- Note There are indications the
isValid(int)
test may not timeout on invalid connections in some scenarios when using SQL Server Drivers. - A validation timeout may be set explicitly as discussed in the article regarding how to configure custom validation properties. The default timeout is 5 seconds if not otherwise set. Note that enforcing the timeout is the responsibility of the underlying driver implementation.
- This is the recommended class for JDBC 4+ compliant drivers (even where vendor specific validation classes may also exist).
- The following may be used as a workaround if problems are encountered with the driver implementation of the
Connection.isValid(int)
method used by theJDBC4ValidConnectionChecker
class:- org.jboss.jca.adapters.jdbc.extensions.db2.DB2ValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLReplicationValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.oracle.OracleValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker
- org.jboss.jca.adapters.jdbc.extensions.sybase.SybaseValidConnectionChecker
- This is the preferred mechanism (instead of
-
<check-valid-connection-sql>some arbitrary sql</check-valid-connection-sql>
- DO NOT USE
check-valid-connection-sql
if a suitable validation class (see above) exists. - This may be used to specify an SQL statement to validate the connection for drivers which are not JDBC4 compliant or for which no suitable validation class exists.
- DO NOT USE
NOTE : that it is not valid to use both a valid-connection-checker
class and check-valid-connection-sql
for the same pool.
2) Select ONE of the following validation methods (timing of the validation):
-
<validate-on-match>true</validate-on-match>
This will validate the connection each time it is checked out from the pool. This is the preferred approach as it can greatly reduce (compared tobackground-validation
) the window of time during which connections may fail between validation and the time the connections are provided to application code. Please refer to this solution for the default values. If this is set to "true", and a validation mechanism is specified as described in step 2 (below), then if the connection taken from the pool is not valid then another is selected from the pool and validated. If that connection is not valid then another connection from the pool is selected. This process continues until a valid connection can be found. (Note: If you do not wish to cycle through every connection in the pool you can use the<use-fast-fail>
option.) If none of the connections in the pool are valid then a new connection will be created. If creating a new connection fails then an exception will be returned to the application requesting the connection. Note, each time a connection is deemed invalid a WARN message will be issued to the log. -
<background-validation>true</background-validation>
When this is set to "true" setvalidate-on-match
to "false." Use<background-validation-millis>
to tune how often validation runs.Explicit configuration of
<background-validation-millis>
to a value greater than 0 is MANDATORY when using background validation. If no value is specified, the default value is 0 which will disable validation. There is no generic/universal recommendation for the value. The risk of encountering invalid connections in the application (which may result in transaction failure, rollback and costly retry) must be weighed against the potential cost of background validation for a large set of idle connections (which may generate significant network traffic, etc.). The value must also be configured with consideration for external timeouts configuration (in the network, on the database server, etc.). For instance, if something in the network or database server is configured to time out "idle" connections after 10 minutes, a background validation frequency of 15 or 20 minutes may increase the likelihood of the application encountering connections that have been terminated. Instead, it might be better to configure validation to run every 5 to 7 minutes. This would reduce the chance of missing an externally timed out connection. Because background validation will generate activity on the connections, this will tend to prevent externally initiated timeout. In some cases, configuration of the JBoss EAP idle-timeout-minutes configuration (set lower than any possible external timeout) may work well alongside background validation. Note that the JBoss idle timeout mechanism is not impacted by how often background scans are performed. The "clock" for idle timeout begins the moment a connection is returned to the pool after use and is not reset when background validation occurs for that connection. The<background-validation-millis>
should not be the same as your<idle-timeout-minutes>
value. -
NOTE : that it is not valid to use both
validate-on-match
andbackground-validation
for the same pool. Select one. If both are enabled, onlyvalidate-on-match
works, butbackground-validation
is ignored and not performed in EAP7. -
NOTE ::
- If the minimal performance hit on each connection request is not a concern then using
validate-on-match
is preferred rather thanbackground-validation
. See also the discussion of the implications of using background-validation vs validate-on-match. - The lower the
background-validation-millis
value the more often the pool will be validated which will take up more database resources. Also the lower the value the sooner invalid connections will be evicted from the pool. On the one hand, too low of a value (meaning validation is occurring frequently) can stress the connection pool resources. On the other hand, if the value is set too high (meaning validation is not occurring frequently enough) then the dead connections will go undetected for longer periods. Therefore it is a balancing act to determine the correct value for a particular system.
- If the minimal performance hit on each connection request is not a concern then using
3) Set exception sorter <exception-sorter class-name="x.y.z" />
- Use this so that fatal exceptions can be detected properly and the connections that throw them can be cleaned up. When an exception is recognized as fatal by the exception sorter, the connection from which it came is closed immediately, even if the connection is enlisted in a transaction. Notification of a fatal exception is then forwarded to the managing pool in order to enforce the pool flush strategy.
-
EAP 6 and later releases provide the following exception sorters:
- org.jboss.jca.adapters.jdbc.extensions.db2.DB2ExceptionSorter
- org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLExceptionSorter (EAP 6.4 and later only)
- org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter
- org.jboss.jca.adapters.jdbc.extensions.oracle.OracleExceptionSorter
- org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter
- org.jboss.jca.adapters.jdbc.extensions.sybase.SybaseExceptionSorter
- org.jboss.jca.adapters.jdbc.extensions.novendor.ListExceptionSorter (EAP 6.4.8 and later only)
-
Some datasource types (in some EAP releases) may lack an exception sorter. Connection validation will work without an exception sorter because it is based on the success or failure of the connection test method (see the validation methods discussed above). Datasources without an exception sorter will use the
NullExceptionSorter
(which returnsfalse
for theboolean isExceptionFatal(SQLException)
test) and will be unable to notify the pool of fatal connection errors so flush strategies other thanFailingConnectionOnly
will be ineffective. For such datasources, the ListExceptionSorter may be used to specify vendor specific error codes used to identify fatal connection errors.
NOTE :
- The above referenced configuration will be placed within the
<validation>..</validation>
section in the relevant<datasource>
section under the datasource subsystem. Please refer to the datasource examples for your EAP version (EAP 7 or EAP 6) for detailed example settings. See below for a simple JBoss CLI examples. - Is is not necessary to specify a stale-connection-checker class unless the application is specifically coded to check for stale connection exceptions.
Create a New Fault Tolerant Datasource using JBoss CLI
# Standalone configuration example for *new* datasource (omitting connection-url, user-name, password, driver-name, etc.)
[standalone@localhost:9999 /] data-source add --name=Oracle --jndi-name=java:jboss/datasources/oracle ... --valid-connection-checker-class-name=org.jboss.jca.adapters.jdbc.extensions.novendor.JDBC4ValidConnectionChecker --validate-on-match=true --background-validation=false --exception-sorter-class-name=org.jboss.jca.adapters.jdbc.extensions.oracle.OracleExceptionSorter --enabled=true
Add Fault Tolerance to an Existing Datasource using JBoss CLI
# Standalone configuration example for existing datasource pool named 'Oracle'
[standalone@localhost:9999 /] /subsystem=datasources/data-source=Oracle:write-attribute(name=valid-connection-checker-class-name, value=org.jboss.jca.adapters.jdbc.extensions.novendor.JDBC4ValidConnectionChecker)
{
"outcome" => "success",
"response-headers" => {
"operation-requires-reload" => true,
"process-state" => "reload-required"
}
}
[standalone@localhost:9999 /] /subsystem=datasources/data-source=Oracle:write-attribute(name=validate-on-match, value=true)
{
"outcome" => "success",
"response-headers" => {
"operation-requires-reload" => true,
"process-state" => "reload-required"
}
}
[standalone@localhost:9999 /] /subsystem=datasources/data-source=Oracle:write-attribute(name=background-validation, value=false)
{
"outcome" => "success",
"response-headers" => {
"operation-requires-reload" => true,
"process-state" => "reload-required"
}
}
[standalone@localhost:9999 /] /subsystem=datasources/data-source=Oracle:write-attribute(name=exception-sorter-class-name, value=org.jboss.jca.adapters.jdbc.extensions.oracle.OracleExceptionSorter)
{
"outcome" => "success",
"response-headers" => {
"operation-requires-reload" => true,
"process-state" => "reload-required"
}
}
[standalone@localhost:9999 /] reload
Configure Fault Tolerance for a JBoss EAP for OpenShift Image
With current JBoss EAP for OpenShift images published in the Red Hat respository, the following environment parameters may be used to configure fault tolerance2.
<DATASOURCE_PREFIX>_CONNECTION_CHECKER=<DATASOURCE_TYPE_SPECIFIC_CONNECTION_CHECKER_CLASS>
<DATASOURCE_PREFIX>_EXCEPTION_SORTER=<DATASOURCE_TYPE_SPECIFIC_EXCEPTION_SORTER_CLASS>
For instance with an external Oracle datasource for which the prefix is ORADS the following would be used:
ORADS_CONNECTION_CHECKER=org.jboss.jca.adapters.jdbc.extensions.novendor.JDBC4ValidConnectionChecker
ORADS_EXCEPTION_SORTER=org.jboss.jca.adapters.jdbc.extensions.oracle.OracleExceptionSorter
Note that this will configure the default mechanism which uses validate-on-match
. If background-validation
is desired (background validation is not usually recommended), additional properties should be used to disable the recommended configuration and use background validation instead:
<DATASOURCE_PREFIX>_BACKGROUND_VALIDATION=true
<DATASOURCE_PREFIX>_BACKGROUND_VALIDATION_MILLIS=120000
(this will set the validation frequency to 2 minutes, the default if not specified explicitly is 10000 milliseconds/10 seconds which is likely too frequent for most systems)
Depending on how the container is created/launched it might be necessary to provide the configuration:
- In an environment property file using
--env-file <file>
- Using individual
--env <PROPERTY>=<VALUE>
parameters -
Using a custom
standalone-openshift.xml
file (see discussion/examples of XML configuration above) -
NOTE : Has a datasource been affected and does the boss have caching behavior for the
datasource
connection? does this mean that one mustrestart
the server after changing the password? Yes, because the changes are not yet at runtime. Also, theconnection pool
reservation had already been made with theold password
.
-
The
JDBC4ValidConnectionChecker
uses the JDBC 4 Connection.isValid(int) API which may often be faster than validation by SQL command execution. The (older) validation class for Oracle uses an Oracle specific "ping" method. Other validation classes may simply send SQL if no optimized validation mechanism exists. In most cases (for JDBC 4+ compliant drivers), however,org.jboss.jca.adapters.jdbc.extensions.novendor.JDBC4ValidConnectionChecker
is preferred. ↩︎ -
See also section 7.6.1.2 of the EAP/OCP Getting Started Guide. ↩︎
Diagnostic Steps
Validation activity may be traced/verified using one or more of the below
- Background validation may be monitored via
TRACE
level logging enabled for one or both of the following logger categoriesorg.jboss.jca.core.connectionmanager.pool.strategy.OnePool
(pool specific activity)org.jboss.jca.core.connectionmanager.pool.validator.ConnectionValidator
(background validation thread activity)
-
One or more Byteman rules similar to the below may be used to trace firing of validation
RULE Pool.Background.Validate INTERFACE org.jboss.jca.core.connectionmanager.pool.mcp.ManagedConnectionPool METHOD validateConnections IF true # Relevant only for background-validation DO traceStack("[BMAN] Pool(" + $0.pool.getName() + ") "); ENDRULE RULE Connection.Validate INTERFACE org.jboss.jca.adapters.jdbc.spi.ValidConnectionChecker METHOD isValidConnection AT EXIT IF true # Method returns an exception on any connection validation failure # Relevant for both validate-on-match and background-validation DO traceStack("[BMAN] isValidConnection(" + $1 + ") => " + $! + "\n"); ENDRULE
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.
Comments