Mysql jconnector在com.mysql.jdbc.utils.ReadAheadInputStream.fill()中花费了50%的时间。

12
我正在为使用Spring、Hibernate和mysql-java-connector的应用程序进行性能分析。VisualVM显示:当有1000个并行连接在读取时,超过50%的CPU时间都花费在com.myql.jdbc.utils.ReadAheadInputStream.fill()方法中。
是否有任何优化措施可以加快速度?

1
听起来好像只是在等待数据库返回数据。问题可能出在数据库本身,你有没有看到MySQL和运行它的服务器的任何使用数据?1000个并发连接会使用相当多的内存...如果必须访问磁盘进行这些查询,那么数据库将需要相当长的时间才能响应。 - Augusto
当使用Hibernate时,这是很常见的,因为它保持连接/流作为其实时填充的一部分。使用Hibernate时,这和许多其他细节都不太高效。 - BrianC
它花费了50%的时间从网络中读取。这不是你可以通过任何其他方式加速的,除非使用更快的网络或返回较小的查询结果。 - user207421
@BrianC 有没有什么方法可以针对这种情况优化Hibernate本身? - zx_wing
不,Hibernate 是问题所在。 - BrianC
显示剩余6条评论
3个回答

3
VisualVM在JVM认为它可以运行的任何线程上计算CPU时间。这意味着除了等待锁的线程,包括在内核中等待I/O的线程都被视为可运行。这就是com.myql.jdbc.utils.ReadAheadInputStream.fill()中大量CPU使用率的来源。因此,您不是面临一个CPU问题,而是I/O问题。
在JVM端有一些可以做的事情,但优化并不直观:
  1. 调整连接池大小。1000个并发查询是很多的。除非您的MySQL实例真的很大,否则它会难以处理那么高的负载,并花费大量时间在查询之间切换。试着减少池的大小,到250甚至50,并进行基准测试。
  2. 执行更少或更小的查询。如果您的应用程序很小,可能很明显每个查询的每一行都是必需的,但也许您的应用程序比那更大。是否有不同的地方来查询相同的数据,或者可以将两个不同的查询合并成一个可以同时满足两个查询的查询?

2
除了其他建议之外,还要考虑尝试使用更少的连接(即20个)进行实验。很可能处理如此大量的打开连接的开销会稍微影响您的性能分析观察。
最重要的是,确保您正在使用最新版本的Hibernate ORM。我们使5.0+版本比以前的版本智能得多,特别是在性能方面的改进;-) 改进每天都会应用,因此保持最新或至少尝试最新的版本可能是一个简单的胜利。

0

没有更多的信息,很难回答你的问题。以下是需要满足的一些信息。

  1. 你的CPU时间估计是绝对还是相对的?如果fill()方法使用了系统可用CPU时间的一半,这似乎很奇怪。但如果这个数字是使用VisualVM获取的,它报告相对于应用程序中花费的时间的使用时间,那么你的应用程序的其余部分可能没有做重要的工作吗?
  2. 这些分析测量是否使用系统级工具进行确认?如果你在Linux上,可以使用pidstatmpstatsar进行交叉检查。我曾经看到VisualVM将在SocketInputStream.socketRead0()方法中花费的时间标记为CPU时间,但这并未得到pidstat的确认。我猜测这是VisualVM本身或JVM行为中某些测量近似的结果。因此,使用操作系统工具进行交叉检查总是一个好主意。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接