持久化用的 Hibernate,连接池用的 Hikari,连接池大小设置为 800 。场景是使用 csv 批量导入上万条记录,每条记录不是简单的保存到数据库,可能会涉及到多次数据库查询或者更新操作。
在这种前提之下,当我将这些动作都放到一个事务中去处理的时候,后台会报如下的错误:
Caused by: java.sql.SQLTransientConnectionException: HikariPool-3 - Connection is not available, request timed out after 20001ms.
21:37:18,591 ERROR [stderr] (default task-3) at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:695)
21:37:18,591 ERROR [stderr] (default task-3) at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:197)
21:37:18,591 ERROR [stderr] (default task-3) at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:162)
21:37:18,591 ERROR [stderr] (default task-3) at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:100)
21:37:18,592 ERROR [stderr] (default task-3) at org.hibernate.hikaricp.internal.HikariCPConnectionProvider.getConnection(HikariCPConnectionProvider.java:77)
21:37:18,592 ERROR [stderr] (default task-3) at org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider.getConnection(AbstractMultiTenantConnectionProvider.java:36)
使用 show processlist 观察 mysql 连接的时候,某个瞬间会产生大量的 sleep 连接。
现在我的疑问是,sleep 连接是怎么才会产生的? 如果我仅仅只是在循环中执行一万次数据库查询操作,MySQL 连接没有什么波动,而当我在使用事务执行某个耗时任务时(这个任务中会执行查询数据库的操作),就会产生大量的 sleep 连接?
谁能帮忙解释一下?
1
gjkv86 2021-01-21 22:15:14 +08:00 via iPhone
800 个连接太多了 什么数据库禁得起这么造啊
|
2
kosmosr 2021-01-21 22:35:51 +08:00 via Android
连接池原理,预申请,避免频繁新建销毁连接;而且连接池大小不是越大越好
|
3
CEBBCAT 2021-01-21 22:52:28 +08:00 via Android
@gjkv86 800 个很多吗?刚入行的小菜鸡,前两天看到同事在讨论,我们有的 MySQL 实例链接数上限就是 800
|
4
ElmerZhang 2021-01-21 23:06:57 +08:00
@CEBBCAT 一般 SQL 优化的比较好的,连接池设置 10 个就够用了。
我经手过的某系统,单机峰值 QPS 1500,也只使用了不到 10 个连接。 |
5
neoblackcap 2021-01-21 23:09:44 +08:00
如果是在循环中跑事务,那么显然会出现大量 sleep 。毕竟一个连接只能同时处理一个事务啊。你如果快速地提交,显然连接池的连接不够用,那么就会触发大量连接。
你要不将事务的作用域扩大一些?比如分批次导入,一次用一个事务导入 100 条这样? |
6
zoharSoul 2021-01-22 00:29:00 +08:00
Hikari 建议的连接池大小是 10 还是 15 来着
|
7
xcstream 2021-01-22 02:27:57 +08:00
连接池大小设置为 800 噗
|
8
k9982874 2021-01-22 07:26:03 +08:00 via iPhone
楼主: 连接池 800,启动!
mysql: ???我死给你看! |
9
iceneet 2021-01-22 08:30:55 +08:00
???连接池 800 数据库没挂很厉害了!
|
10
40EaE5uJO3Xt1VVa 2021-01-22 09:03:10 +08:00
楼上描述的很准确了,连接池 10-15 就够用的,800mysql 没挂都是他性能好
|
11
cloudhuang 2021-01-22 09:03:37 +08:00
设置线程池,其实一般来说,就设置成 2N | 2N + 1 就可以了,数据库连接池也一样
|
12
jorneyr 2021-01-22 09:09:19 +08:00
看看数据库允许的最大并发连接数是多少。
此外,800 虽然多,但也不算多,我们数据库连接一般会允许最大 2000 。 |
14
mmdsun 2021-01-22 09:54:29 +08:00 via Android
MySQL 连接数
和 Java 数据库连接池不是一个概念吧。 你把链接池改小一下,存活周期改小。 另外 hibernate jpa 这类批量导数据需要关闭 spring.jpa.open-in-view false 不然 session 保存时间太长一直不结束。 |
15
passerbytiny 2021-01-22 10:08:30 +08:00 via Android
上万条记录……每条记录……可能会涉及到多次……查询或者更新……将这些动作都放到一个事务……
你该不会是在循环外面套事务吧,那样的事务太大,压根处理不了。 |
16
WuwuGin 2021-01-22 10:45:31 +08:00
Connection is not available, request timed out after 20001ms.
我怀疑是 mysql 挂了,或者某个表挂了,看看是不是会有死锁产生? |
17
aizya OP @WuwuGin 谢谢,查了没有死锁。 应该是我在处理的时候,把耗时的逻辑放在事务里面去处理了。 但是又不知道该怎么把里面的逻辑拆分出来。
|
18
keepeye 2021-01-22 11:12:17 +08:00
800 有点多,但纯连接应该没事吧,又没跑 sql
|
19
ytll21 2021-01-22 11:40:25 +08:00
你们的数据库就给你这一个系统用吗?你这一个系统就用掉了 800 个。。。还给不给其它系统用呀。。。
|
20
CODEWEA 2021-01-22 13:20:50 +08:00
800 个客户端 你们那个机器行吗?
|