JDBC 连接池调节的最佳实践

在本教程中,我们将讨论确定JDBC 连接池大小的最佳策略。

我们讨论如何设置 JDBC 连接池。通过了解影响连接池大小的因素并遵循调优和监控的最佳实践,我们可以确保健康的数据库连接并提高应用程序性能。

什么是 JDBC 连接池?为什么要使用它?
JDBC 连接池是一种用于有效管理数据库连接的机制。创建数据库连接涉及几个耗时的步骤,例如:

  • 打开与数据库的连接
  • 验证用户身份
  • 创建用于通信的 TCP 套接字
  • 通过套接字发送和接收数据
  • 关闭连接和 TCP 套接字
为每个用户请求重复这些步骤可能效率低下,尤其是对于拥有许多用户的应用程序。JDBC 连接池通过提前创建可重复使用的连接池来解决此问题。当应用程序启动时,它会在池中创建和维护数据库连接。池连接管理器管理这些连接并处理它们的生命周期。

当客户端请求连接时,池管理器会从池中提供一个连接,而不是创建新连接。客户端完成后,连接将返回池中以供重复使用,而不是关闭。这种连接的重复使用可节省时间和资源,从而显著提高应用程序性能。

为什么确定 JDBC 连接池的最佳大小很重要?
确定 JDBC 连接池的最佳大小对于平衡性能和资源利用率至关重要。较小的池可能导致更快的连接访问,但如果没有足够的连接来满足所有请求,则可能导致延迟。相反,较大的池可确保有更多连接可用,从而减少排队时间,但可能会减慢对连接表的访问速度。

下表总结了确定连接池大小时需要考虑的优缺点:

  • 小池    更快地访问连接表    我们可能需要更多连接来满足请求。请求可能会在队列中花费更多时间。
  • 大型池    更多的连接来满足请求。请求在队列中花费的时间更少(甚至没有)    连接表访问速度较慢

 确定 JDBC 连接池大小时要考虑的关键点
在决定池大小时,我们需要考虑几个因素。首先,我们应该评估平均事务响应时间和数据库查询所花费的时间。负载测试可以帮助确定这些时间,建议在计算池大小时额外增加 25% 的容量以处理意外负载。其次,连接池应该能够根据实际需求增长和缩小。我们还可以使用日志语句或 JMX 监视来监视系统,以动态调整池大小。

此外,我们还应该考虑每次页面加载执行多少个查询以及每个查询的持续时间。为了获得最佳性能,我们从几个连接开始,然后逐渐增加。每个节点有 8 到 16 个连接的池通常是最佳的。我们还可以根据监控统计数据调整空闲超时和池调整大小数量值。

控制JDBC连接池的基本设置
这些基本设置控制池大小:

  • Initial and Minimum Pool Size初始和最小池大小:   创建池时的大小及其允许的最小大小
  • Maximum Pool Size最大池大小 :   池大小的上限
  • Pool Resize Quantity池调整数量:    空闲超时到期时要删除的连接数。空闲时间超过超时的连接将被删除,一旦池达到初始和最小池大小,就会停止
  • Max Idle Connections最大空闲连接数:    池中允许的最大空闲连接数。如果空闲连接数超过此限制,则关闭多余的连接,释放资源
  • Min Idle Connections最小空闲连接数 :   池中保留的最小空闲连接数
  • Max Wait Time最长等待时间:    应用程序等待连接可用的最长时间
  • Validation Query验证查询:    用于在将连接移交给应用程序之前验证连接的 SQL 查询


确定 JDBC 连接池大小的最佳实践
以下是调整 JDBC 连接池以确保与数据库实例的健康连接的一些最佳实践。

验证连接 SQL
首先,我们添加一个验证 SQL 查询以启用连接验证。它确保定期测试池中的连接并保持健康。它还可以快速检测并记录数据库故障,使管理员能够立即采取行动。选择最佳验证方法(例如元数据或表查询)。经过充分监控后,关闭连接验证可以进一步提高性能。下面是使用最流行的 JDBC 连接池即Hikari进行配置的示例:

HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:your_database_url");
config.setUsername(
"your_database_username");
config.setPassword(
"your_database_password");
config.setConnectionTestQuery(
"SELECT 1");
HikariDataSource dataSource = new HikariDataSource(config);

最大池大小
我们还可以调整最大池大小,使其足以满足使用该应用程序的用户数量。有必要处理异常负载。即使在非生产环境中,也可能需要多个同时连接:

config.setMaximumPoolSize(20);

最小池大小
然后,我们应该调整最小池大小以适应应用程序的负载。如果多个应用程序/服务器连接到同一个数据库,则具有足够的最小池大小可确保保留的数据库连接可用:

config.setMinimumIdle(10);

连接超时
我们可以考虑的另一个方面是配置阻塞超时(以毫秒为单位),以便连接请求等待连接可用,而不是无限期地等待。建议使用 3 到 5 秒的合理值:

config.setConnectionTimeout(5000);

空闲超时
将空闲超时设置为适合应用程序的值。对于共享数据库,较低的空闲超时(例如 30 秒)可以使空闲连接可供其他应用程序使用。较高的值(例如 120 秒)可以防止专用数据库频繁创建连接:

config.setIdleTimeout(30000);

// or

config.setIdleTimeout(120000);

线程池调优
使用负载/压力测试来估计最小和最大池大小。估计池大小的常用公式是连接数 = (2 * 核心数) + 磁盘数。此公式提供了一个起点,但要求可能因 I/O 阻塞和其他因素而有所不同。从较小的池大小开始,并根据测试逐渐增加。监控工具(如pg_stat_activity)可以帮助确定连接是否空闲过多,这表明需要减小池大小:

int coreCount = Runtime.getRuntime().availableProcessors();
int numberOfDisks = 2; // assuming two no. of disc
int connections = (2 * coreCount) + numberOfDisks;
config.setMaximumPoolSize(connections);
config.setMinimumIdle(connections / 2);

事务隔离级别
选择满足并发性和一致性需求的最佳隔离级别。除非必要,否则请避免指定隔离级别。如果指定,请将不以编程方式更改隔离级别的应用程序的“保证隔离级别”设置为false :

try (Connection conn = dataSource.getConnection()) {
    conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
} catch (SQLException e) {
    e.printStackTrace();
}