1、简介 {#1简介}
本文将带你了解调整 JDBC 连接池大小的最佳策略。
2、什么是 JDBC 连接池,为什么要使用它? {#2什么是-jdbc-连接池为什么要使用它}
JDBC 连接池是一种用于有效管理数据库连接的机制。创建数据库连接需要几个耗时的步骤,如
- 打开数据库连接
- 验证用户身份
- 创建用于通信的 TCP Sokcet 套接字
- 通过套接字收发数据
- 关闭连接和 TCP Sokcet 套接字
为每个用户请求重复这些步骤的效率可能会很低,尤其是对于有许多用户的应用。JDBC 连接池通过提前创建一个可重复使用的连接池来解决这个问题。当应用程序启动时,它会在池中创建并维护数据库连接。池连接管理器负责管理这些连接并处理其生命周期。
当客户端请求连接时,连接池管理器会从连接池中提供一个连接,而不是创建一个新的连接。一旦客户端完成操作,连接就会返回池中重复使用,而不是关闭。这种连接的重复使用节省了时间和资源,大大提高了应用程序的性能。
3、为什么 JDBC 连接池的大小对应用来说很重要? {#3为什么-jdbc-连接池的大小对应用来说很重要}
确定 JDBC 连接池的最佳大小对于平衡性能和资源利用率至关重要。较小的连接池可能会加快连接访问速度,但如果没有足够的连接来满足所有请求,则可能导致延迟。相反,较大的连接池可确保有更多连接可用,减少在队列中花费的时间,但可能会降低连接表的访问速度。
"连接表" 通常指的是管理和跟踪数据库连接的内部数据结构。它记录了当前连接的状态(如空闲、使用中等)以及相关的元数据,以便有效地分配和管理连接。这个"表"并不是数据库中的实际表,而是连接池实现中的一个逻辑概念。
下表总结了在确定连接池大小时需要考虑的利弊:
| 连接池大小 | 优点 | 缺点 | |--------|-------------------------------|--------------------------------| | 较小的连接池 | 更快地访问连接表 | 可能需要更多连接来满足请求。请求在队列中停留的时间可能会更长 | | 较大的连接池 | 有更多连接来满足请求。请求在队列中花费的时间减少(或没有) | 降低访问连接表的速度 |
4、确定 JDBC 连接池大小时应考虑的要点 {#4确定-jdbc-连接池大小时应考虑的要点}
在确定池大小时,需要考虑几个因素。首先,应该评估平均事务响应时间和花费在数据库查询上的时间。负载测试可以帮助确定这些时间,建议在计算连接池大小时再增加 25% 的容量,以应对意外负载。其次,连接池应能根据实际需要进行增减。我们可以使用日志或 JMX 监视来监控系统,从而动态调整池的大小。
此外,还应考虑每次页面加载执行多少次查询以及每次查询的持续时间。为了获得最佳性能,我们可以从少量连接开始,然后逐渐增加。每个节点 8 到 16 个连接的池通常是最佳的。我们还可以根据监控统计数据调整空闲超时(Idle Timeout )和池大小调整数量(Pool Resize Quantity)值。
5、JDBC 连接池的基本控制设置 {#5jdbc-连接池的基本控制设置}
这些基本设置可控制池的大小:
| 连接池属性 | 说明 | |----------|--------------------------------------------------------| | 初始和最少连接数 | 池创建时的大小及其允许的最小连接数量 | | 池最大连接数 | 连接池可维护的最大连接数量 | | 池大小调整数量 | 空闲超时时要移除的连接数。闲置时间超过超时的连接将被移除,一旦连接池达到初始和最小连接池大小,就会停止移除。 | | 最大空闲连接数 | 池中允许的最大闲置连接数。如果闲置连接数超过此限制,多余的连接将被关闭,从而释放资源 | | 最小空闲连接数 | 在连接池中保留的空闲连接的最小数量 | | 最大等待时间 | 应用等待连接可用的最长时间 | | 验证查询 | 用于验证连接的 SQL 查询,然后再将其交给应用 |
6、调整 JDBC 连接池大小的最佳实践 {#6调整-jdbc-连接池大小的最佳实践}
以下是调整 JDBC 连接池以确保与数据库实例之间健康连接的一些最佳实践。
6.1、验证连接的 SQL 语句 {#61验证连接的-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"); // 验证连接的 SQL 语句
HikariDataSource dataSource = new HikariDataSource(config);
6.2、最大连接池大小 {#62最大连接池大小}
我们还可以调整最大连接池大小,使其足够满足应用的用户数量。这对处理突发负载是必要的。即使在非生产环境中,也可能需要多个同时连接。
config.setMaximumPoolSize(20);
6.3、最小连接池大小 {#63最小连接池大小}
接下来,应该调整最小连接池大小以适应应用程序的负载。如果多个应用程序/服务器连接到同一个数据库,确保有足够的最小连接池大小可以保证保留的数据库连接可用:
config.setMinimumIdle(10);
6.4、连接超时 {#64连接超时}
我们可以考虑的另一个方面是配置以毫秒为单位的阻塞超时,这样连接请求在等待连接可用时就不会无限期地等待。建议使用 3 至 5 秒的合理值:
config.setConnectionTimeout(5000);
6.5、空闲超时 {#65空闲超时}
将空闲超时设置为适合应用程序的值。对于共享数据库,较低的空闲超时(如 30 秒)可以为其他应用程序提供空闲连接。对于专用数据库,较高的值(如 120 秒)可防止频繁创建连接:
config.setIdleTimeout(30000);
// 或
config.setIdleTimeout(120000);
6.6、线程池调整 {#66线程池调整}
使用负载/压力测试来估算最小和最大池大小。估算池大小的常用公式是 连接数 = (2 * 核数) + 磁盘数 。该公式提供了一个起点,但根据 I/O 阻塞和其他因素,需求可能会有所不同。从小规模连接池开始,根据测试情况逐步增加。pg_stat_activity 等监控工具可以帮助确定连接是否闲置过多,从而表明需要减少池的大小:
int coreCount = Runtime.getRuntime().availableProcessors();
int numberOfDisks = 2; // 假设有两个磁盘
int connections = (2 * coreCount) + numberOfDisks;
config.setMaximumPoolSize(connections);
config.setMinimumIdle(connections / 2);
6.7、事务隔离级别 {#67事务隔离级别}
选择能满足并发性和一致性需求的最佳隔离级别。除非必要,否则避免指定隔离级别。如果指定了隔离级别,请将 "保证隔离级别(Isolation Level Guaranteed)" 设置为 false
,以用于不以编程方式更改隔离级别的应用:
try (Connection conn = dataSource.getConnection()) {
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
} catch (SQLException e) {
e.printStackTrace();
}
7、总结 {#7总结}
本文介绍了调整 JDBC 连接池大小的最佳实践,通过了解影响连接池大小的因素,并遵循调整和监控的最佳实践,可以确保数据库连接的健康和提高的应用程序性能
Ref:https://www.baeldung.com/java-best-practices-jdbc-connection-pool