我们有一个使用 REST 服务的 java 应用程序
oracle.ucp.jdbc.PoolDataSource
from: com.oracle.ojdbc:ojdbc10:jar:19.3.0.0
人流量不是很大, 通常一次只运行一个请求, 有时会有几个请求并行运行。 每个请求通常需要 0.2 秒到 10 秒的时间来执行, 取决于调用哪个方法。
我们遇到的问题似乎是我们正在穿越防火墙, 这将在 60 分钟后断开/断开打开但空闲的连接。
在 PoolDataSource 上,我设置了这些属性:
pds.setInitialPoolSize(6);
pds.setMinPoolSize(6);
pds.setMaxPoolSize(12);
pds.setTimeoutCheckInterval(20);
pds.setInactiveConnectionTimeout(60);
pds.setTimeToLiveConnectionTimeout(60);
注意,最后 3 个属性值以 秒为单位 (因此,waaaaay 小于防火墙中的 60 分钟限制) 因此,通过这些设置,我希望防火墙不会出现问题, 因为(根据我对文档的理解)无论如何每个连接 应该在一两分钟内失效(关闭+重新创建),不是吗?
但是,我们有时还是会看到:
SQLRecoverableException: Closed Connection
在日志中,请求将失败, 这让我开始研究游泳池的行为细节......
监控 v$session,当我运行最多 3 个并行请求的测试用例时,我可以看到,正如预期的那样,启动应用程序时创建了 6 个会话。
但是——池将仅调用三个最低可用的(首先创建的) 一遍又一遍的连接。
因此,如果在超过 60 分钟后调用 4 个或更多并行请求,池将发出比参数指定的连接更旧的连接:
pds.setInactiveConnectionTimeout(60);
pds.setTimeToLiveConnectionTimeout(60);
由于防火墙规则,这将导致 SQLRecoverableException: Closed Connection。
所以我想知道,是否有一种方法可以强制“轮换”可用连接(如负载均衡器),以便所有都能得到同等的使用?
或者其他合理的方法来解决这个问题?
编辑:嗯...经过另一次测试,我现在意识到可能可以设置:
pds.setInitialPoolSize(0);
pds.setMinPoolSize(0);
然后池可以在几分钟内下降到 0 个连接,因此即使一段时间内没有请求或只有一个请求进来,连接也不会过时...但是这部分违背了连接池的目的......
所以,这似乎有点奇怪......看起来不像文档中的预期行为:
“setInactiveConnectionTimeout:设置非活动连接超时时间。该超时时间决定可用连接在从池中删除之前在连接池中保留的时间。”
只要并行传入请求的数量永远不会低于 minPoolSize,这就是唯一正确的...令人困惑,并且在文档中没有提及,我可以看到... (实际上,如果这是真的,minPoolSize 就变得毫无意义)
任何人都可以透露一些信息吗?
https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html
我认为发生上述问题是因为 UCP 不会将其池大小缩小到最小值以下,并且如果池只有最小池大小的连接,它会忽略非活动连接超时。如果由于不活动的计时器而缩小到最小池大小以下,那么即使池空闲,也会有大量新的打开和关闭的连接。 如果防火墙关闭空闲连接,我认为您可以通过将 JDBC 连接属性“oracle.net.keepAlive”值设置为“true”来启用 tcp keepAlive。您可以通过调用 setConnectionProperties(props) API 在 UCP 数据源中传入此属性。
PoolDataSouce pds = .....
Properties props = new Properties();
props.setProperty("oracle.net.keepAlive", "true");
pds.setConnectionProperties(props);