Mysql 连接器在 com.mysql.jdbc.utils.ReadAhead InputStream.fill() 中花费 50% 的时间
Posted
技术标签:
【中文标题】Mysql 连接器在 com.mysql.jdbc.utils.ReadAhead InputStream.fill() 中花费 50% 的时间【英文标题】:Mysql jconnector spends 50% time in com.myql.jdbc.utils.ReadAheadInputStream.fill() 【发布时间】:2014-10-10 22:48:54 【问题描述】:我正在分析我的应用程序,它使用 Spring、Hibernate 和 mysql-java-connector。 VisualVM 显示当有 1000 个并行连接进行读取时,超过 50% 的 CPU 时间花费在 com.myql.jdbc.utils.ReadAheadInputStream.fill()
方法上。
有没有什么优化让它更快?
【问题讨论】:
您的日志记录设置为调试级别吗?你是在用这些连接做点什么,还是只是在做虚拟选择?此外,此类委托给另一个输入流。查看其中一个调用的堆栈跟踪会很有帮助。 @Augusto 我正在做真正的查询,每次返回大约 200 行。你的意思是什么日志记录?在休眠或mysql上?真正的方法是java.net.SocketInputStream.read。我用谷歌搜索,但没有太多关于如何改进它的提示。 听起来确实是在等待数据库返回数据。问题可能出在数据库本身,你有没有看到 MySQL 的任何使用数据和它运行的盒子? 1000 个并发连接将使用大量内存。如果它必须访问磁盘以进行这些查询,那么数据库将需要很长时间才能响应。 @Augusto 是的,它似乎是。我换了更强大的机器,性能越来越高 运气好能解决这个问题吗? 【参考方案1】:只要 JVM 认为线程可运行,VisualVM 就会将线程计为使用 CPU 时间。这意味着任何不等待锁的线程或多或少都被认为是可运行的,包括内核中等待 I/O 的线程!这就是com.myql.jdbc.utils.ReadAheadInputStream.fill()
中大量 CPU 使用率的来源。所以不是 CPU 问题,而是 I/O 问题。
你可以在 JVM 端做一些事情,但不是很多直接的优化:
-
调整连接池大小。 1,000 个并发查询是 很多。除非您的 MySQL 实例真正庞大,否则它将难以处理该级别的负载,并且在查询之间切换会占用大量时间。尝试将池大小降低到 250 甚至 50,并在那里进行基准测试。
执行更少或更小的查询。如果您的应用程序很小,那么每个查询中的每一行都是必要的,但您的应用程序可能比这更大。是查询相同数据的不同地方,还是可以将两个不同的查询组合成一个同时满足两者的查询?
【讨论】:
【参考方案2】:除了其他建议之外,还可以考虑尝试使用更少的连接(即 20)。 处理如此大量的打开连接的开销很可能会稍微欺骗您的分析观察。
最重要的是,请确保您使用的是最新版本的 Hibernate ORM。 我们使 5.0+ 版本比以前的版本更智能,尤其是在性能改进方面 ;-) 每天都会应用改进,因此保持最新或至少尝试最新版本可能很容易获胜。
【讨论】:
【参考方案3】:如果没有其他信息,很难回答您的问题。这里有一些之前应该满足的信息需求。
-
您对 CPU 时间的估计是绝对的还是相对的?如果
fill()
方法使用了系统可用 CPU 时间的一半,这似乎很奇怪。但是,如果这个数字是使用 VisualVM 获得的,它报告使用时间相对于在应用程序中花费的时间,那可能是您的应用程序的其余部分没有做重要的工作?
是否使用系统级工具确认了这些分析测量?如果您在 Linux 上,您可以使用 pidstat
、mpstat
和 sar
进行交叉检查。我已经看到 VisualVM 将 SocketInputStream.socketRead0()
方法中花费的时间标记为 CPU 时间,pidstat
没有确认这一点。我猜这是 VisualVM 本身或 JVM 行为中的一些测量近似值的结果。因此,最好使用操作系统工具进行交叉检查。
【讨论】:
以上是关于Mysql 连接器在 com.mysql.jdbc.utils.ReadAhead InputStream.fill() 中花费 50% 的时间的主要内容,如果未能解决你的问题,请参考以下文章
Java 中的 MySQL 连接错误 - com.mysql.jdbc.Driver
Mysql连接问题:com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException