Java 操作 MySQL 的时候,为什么瞬间会产生大量的 sleep 的连接。

2021-01-21 22:04:09 +08:00
 aizya

持久化用的 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 连接?

谁能帮忙解释一下?

4176 次点击
所在节点    Java
20 条回复
gjkv86
2021-01-21 22:15:14 +08:00
800 个连接太多了 什么数据库禁得起这么造啊
kosmosr
2021-01-21 22:35:51 +08:00
连接池原理,预申请,避免频繁新建销毁连接;而且连接池大小不是越大越好
CEBBCAT
2021-01-21 22:52:28 +08:00
@gjkv86 800 个很多吗?刚入行的小菜鸡,前两天看到同事在讨论,我们有的 MySQL 实例链接数上限就是 800
ElmerZhang
2021-01-21 23:06:57 +08:00
@CEBBCAT 一般 SQL 优化的比较好的,连接池设置 10 个就够用了。
我经手过的某系统,单机峰值 QPS 1500,也只使用了不到 10 个连接。
neoblackcap
2021-01-21 23:09:44 +08:00
如果是在循环中跑事务,那么显然会出现大量 sleep 。毕竟一个连接只能同时处理一个事务啊。你如果快速地提交,显然连接池的连接不够用,那么就会触发大量连接。
你要不将事务的作用域扩大一些?比如分批次导入,一次用一个事务导入 100 条这样?
zoharSoul
2021-01-22 00:29:00 +08:00
Hikari 建议的连接池大小是 10 还是 15 来着
xcstream
2021-01-22 02:27:57 +08:00
连接池大小设置为 800 噗
k9982874
2021-01-22 07:26:03 +08:00
楼主: 连接池 800,启动!
mysql: ???我死给你看!
iceneet
2021-01-22 08:30:55 +08:00
???连接池 800 数据库没挂很厉害了!
40EaE5uJO3Xt1VVa
2021-01-22 09:03:10 +08:00
楼上描述的很准确了,连接池 10-15 就够用的,800mysql 没挂都是他性能好
cloudhuang
2021-01-22 09:03:37 +08:00
设置线程池,其实一般来说,就设置成 2N | 2N + 1 就可以了,数据库连接池也一样
jorneyr
2021-01-22 09:09:19 +08:00
看看数据库允许的最大并发连接数是多少。

此外,800 虽然多,但也不算多,我们数据库连接一般会允许最大 2000 。
supuwoerc
2021-01-22 09:47:33 +08:00
@CEBBCAT 震惊
mmdsun
2021-01-22 09:54:29 +08:00
MySQL 连接数
和 Java 数据库连接池不是一个概念吧。


你把链接池改小一下,存活周期改小。

另外 hibernate jpa 这类批量导数据需要关闭
spring.jpa.open-in-view false

不然 session 保存时间太长一直不结束。
passerbytiny
2021-01-22 10:08:30 +08:00
上万条记录……每条记录……可能会涉及到多次……查询或者更新……将这些动作都放到一个事务……

你该不会是在循环外面套事务吧,那样的事务太大,压根处理不了。
WuwuGin
2021-01-22 10:45:31 +08:00
Connection is not available, request timed out after 20001ms.
我怀疑是 mysql 挂了,或者某个表挂了,看看是不是会有死锁产生?
aizya
2021-01-22 11:09:52 +08:00
@WuwuGin 谢谢,查了没有死锁。 应该是我在处理的时候,把耗时的逻辑放在事务里面去处理了。 但是又不知道该怎么把里面的逻辑拆分出来。
keepeye
2021-01-22 11:12:17 +08:00
800 有点多,但纯连接应该没事吧,又没跑 sql
ytll21
2021-01-22 11:40:25 +08:00
你们的数据库就给你这一个系统用吗?你这一个系统就用掉了 800 个。。。还给不给其它系统用呀。。。
CODEWEA
2021-01-22 13:20:50 +08:00
800 个客户端 你们那个机器行吗?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/747202

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX