是的,这是有意的。引用文档 https://github.com/brettwooldridge/HikariCP:
此属性控制池允许达到的最大大小,包括空闲连接和正在使用的连接。基本上这个值将决定到数据库后端的实际连接的最大数量。合理的值最好由您的执行环境决定。当池达到此大小并且没有可用的空闲连接时,调用getConnection()
将阻塞最多connectionTimeout
超时前的毫秒数。请阅读关于池大小 https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing. 默认值:10
So basically, when all 300 connections are in use, and you are trying to make your 301st connection, Hikari won't create a new one (as maximumPoolSize
is the absolute maximum), but it will rather wait (by default 30 seconds) until a connection is available again.
这也解释了为什么您会收到您提到的异常,因为默认情况下(当未配置maximumPoolSize
) 是 10 个连接,您可能会立即达到。
要解决此问题,您必须找出这些连接被阻止超过 30 秒的原因。即使在1000个并发用户的情况下,如果你的查询花费几毫秒或最多几秒应该没有问题。
增加池大小
如果您正在调用非常复杂且需要很长时间的查询,则有几种可能性。第一个是增加池大小。然而这却是不建议,因为计算最大池大小的推荐公式是:
connections = ((core_count * 2) + effective_spindle_count)
引用关于池大小调整 https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing文章:
多年来在许多基准测试中都表现良好的公式是
为了获得最佳吞吐量,活动连接的数量应该在某个地方
靠近((core_count * 2) + effective_spindle_count)
。核心数不应包括
HT 线程,即使启用了超线程。有效主轴数为零,如果
活动数据集已完全缓存,接近实际主轴数
随着缓存命中率下降。 ...到目前为止还没有任何分析
该公式与 SSD 的配合效果如何。
正如同一篇文章中所述,这意味着带有 1 个硬盘的 4 核服务器应该只有大约 10 个连接。即使您可能有更多的核心,我假设您没有足够的核心来保证您正在建立的 300 个连接,更不用说进一步增加它了。
增加连接超时
另一种可能性是增加连接超时。前面提到,当所有连接都在使用时,默认会等待30秒,这就是连接超时。
您可以增加此值,以便应用程序在超时之前等待更长时间。如果您的复杂查询需要 20 秒,并且您有一个包含 300 和 1000 个并发用户的连接池,那么理论上您应该将连接超时配置为至少20 * 1000 / 300 = 67 seconds
.
但请注意,这意味着您的应用程序可能需要很长时间才能向用户显示响应。如果您的连接超时时间为 67 秒,并且在复杂查询完成之前还有 20 秒的时间,则您的用户可能需要等待长达一分半钟。
提高执行时间
如前所述,您的主要目标是找出查询花费如此长时间的原因。连接池为 300,连接超时为 30 秒,并发用户数为 1000,这意味着您的查询至少需要9秒在完成之前,这是很多。
尝试通过以下方式缩短执行时间:
- 添加适当的索引。
- 正确书写您的查询。
- 改进数据库硬件(磁盘、核心、网络……)
- 通过引入分页来限制您正在处理的记录数量,...。
- 分工。查看是否可以将查询拆分为较小的查询,从而产生可以在另一个查询中使用的中间结果,依此类推。只要您不进行事务处理,之间的连接就会被释放,从而允许您以牺牲一些性能为代价来为多个用户提供服务。
- 使用缓存
- 预先计算结果:如果您正在进行一些资源密集型计算,您可以尝试在应用程序不经常使用的时刻预先计算结果,例如。晚上并将这些结果存储在另一个可以轻松查询的表中。
- ...