我有一个Java应用程序作为WAR文件部署到Tomcat中。通过JNDI资源查找到Postgres DB的数据源,并使用Tomcat的默认连接池-DBCP 2。Resource
中的context.xml
定义如下
<Resource name="jdbc/test" auth="Container" type="javax.sql.DataSource"
maxTotal="50" maxIdle="15" maxWaitMillis="10000"
username="test" password="test"
driverClassName="org.postgresql.Driver"
defaultReadOnly="true"
url="jdbc:postgresql://localhost:5432/test?socketTimeout=45"
validationQuery="SELECT 1" testOnBorrow="true" />
有一个名为DbConnectionChecker
的类,该类使用Executors.newSingleThreadScheduledExecutor()
执行程序每隔3秒检查一次DB是否处于活动状态。
public class DbConnectionChecker {
private static final Logger LOG = LoggerFactory.getLogger(DbConnectionChecker.class);
private final ScheduledExecutorService taskExecutor;
private String name;
private DataSource dataSource;
private volatile boolean enabled = false;
public DbConnectionChecker(String name, DataSource dataSource, ScheduledExecutorService taskExecutor, Runnable onConnectionOk,
Runnable onConnectionNoOk) {
this.name = name;
this.dataSource = dataSource;
this.taskExecutor = taskExecutor;
this.taskExecutor.scheduleAtFixedRate(() -> pingConnection(onConnectionOk, onConnectionNoOk), 0l, 3000l, TimeUnit.MILLISECONDS);
}
public void start() {
LOG.info("Starting to check {} connection", name);
enabled = true;
}
public void shutdown() {
taskExecutor.shutdown();
}
public void stop() {
enabled = false;
}
public void pingConnection(Runnable onConnectionOk, Runnable onConnectionNoOk) {
if (!enabled) {
return;
}
try (Connection connection = dataSource.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement("SELECT 1")) {
preparedStatement.executeQuery();
LOG.info("Connection {} OK...", name);
onConnectionOk.run();
} catch (Exception e) {
LOG.info("Connection {} couldn't be created...", name);
onConnectionNoOk.run();
}
}
}
一切开始后,我可以选择一条日志行Connection test OK...
,每3秒打印一次。
到目前为止一切顺利。
现在,我尝试模拟网络故障和无法访问的数据库。我将更改iptables并断开与本地Postgres的连接。
sudo iptables -A INPUT -i lo -p tcp --dport 5432 -j DROP
使用postgres-42.2.9时,一切都会按预期进行,一分钟左右,我就会收到一条日志行Connection test couldn't be created...
。
升级到postgres-42.2.10 +之后-我已经测试了所有最新的次要版本,但此操作中断了。执行程序的线程卡在某些套接字调用中,并在那里等待aprox。放映前30分钟。相关的堆栈跟踪在这里
pool-14-thread-1@12955" prio=5 tid=0x45 nid=NA runnable"pool-14-thread-1@12955" prio=5 tid=0x45 nid=NA runnable java.lang.Thread.State: RUNNABLE at
java.net.SocketInputStream.socketRead0(SocketInputStream.java:-1) at
java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at
java.net.SocketInputStream.read(SocketInputStream.java:171) at
java.net.SocketInputStream.read(SocketInputStream.java:141) at
sun.security.ssl.InputRecord.readFully(InputRecord.java:465) at
sun.security.ssl.InputRecord.read(InputRecord.java:503) at
sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:975) - locked <0x3e55> (a java.lang.Object) at
sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:933) at
sun.security.ssl.AppInputStream.read(AppInputStream.java:105) - locked <0x3e37> (a sun.security.ssl.AppInputStream) at
org.postgresql.core.VisibleBufferedInputStream.readMore(VisibleBufferedInputStream.java:161) at
org.postgresql.core.VisibleBufferedInputStream.ensureBytes(VisibleBufferedInputStream.java:128) at
org.postgresql.core.VisibleBufferedInputStream.ensureBytes(VisibleBufferedInputStream.java:113) at
org.postgresql.core.VisibleBufferedInputStream.read(VisibleBufferedInputStream.java:73) at
org.postgresql.core.PGStream.receiveChar(PGStream.java:370) at
org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2043) at
org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:312) - locked <0x3e3a> (a org.postgresql.core.v3.QueryExecutorImpl) at
org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:448) at
org.postgresql.jdbc.PgStatement.execute(PgStatement.java:369) at
org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:153) at
org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:103) at
org.apache.tomcat.dbcp.dbcp2.PoolableConnection.validate(PoolableConnection.java:287) at
org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory.validateConnection(PoolableConnectionFactory.java:630) at
org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory.validateObject(PoolableConnectionFactory.java:648) at
org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:476) at
org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:353) at
org.apache.tomcat.dbcp.dbcp2.PoolingDataSource.getConnection(PoolingDataSource.java:134) at
org.apache.tomcat.dbcp.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:753) at
com...db.DbConnectionChecker.pingConnection(DbConnectionChecker.java:49) at
com...db.DbConnectionChecker.lambda$new$0(DbConnectionChecker.java:28) at
com...db.DbConnectionChecker$$Lambda$250.1931785101.run(Unknown Source:-1) at
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at
java.util.concurrent.FutureTask.runAndReset$$$capture(FutureTask.java:308) at
java.util.concurrent.FutureTask.runAndReset(FutureTask.java:-1) at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at
java.lang.Thread.run(Thread.java:748)
最新的postgres驱动程序是否存在问题?是否有我不知道的超时-默认设置?