高CPU,可能是由于上下文切换?

我们的一台服务器在我们的应用程序中遇到了非常高的CPU负载。 我们查看了各种统计数据,并且在查找问题根源时遇到了问题。

目前的理论之一是涉及太multithreading,我们应该尝试减少并发执行线程的数量。 只有一个主线程池,有3000个线程,还有一个使用它的WorkManager(这是Java EE – Glassfish)。 在任何给定时刻,大约需要并行执行大约620个独立的网络IO操作(使用java.NIO也不是一种选择)。 此外,大约有100个操作没有涉及IO,也是并行执行的。

这种结构效率不高,我们想看看它是否真的造成了损害,或者只是不好的做法。 原因是在这个系统中任何变化都非常昂贵(就工时而言)所以我们需要一些问题的证据。

所以现在我们想知道线程的上下文切换是否是原因,因为线程比所需的并发操作多得多。 查看日志,我们发现在给定的秒内平均执行了14个不同的线程。 如果我们考虑到两个CPU的存在(见下文),则每个CPU有7个线程。 这听起来不太多,但我们想validation这一点。

那么 – 我们可以排除上下文切换或太multithreading作为问题吗?

一般细节:

  1. Java 1.5(是的,它已经老了),运行在CentOS 5,64位Linux内核2.6.18-128.el5上
  2. 机器上只有一个Java进程,没有别的。
  3. 两个CPU,在VMware下。
  4. 8GB RAM
  5. 我们没有选择在机器上运行探查器。
  6. 我们没有选择升级Java和OS。

更新如下所述,我们在各种负载的测试服务器上进行了平均负载(使用正常运行时间)和CPU(使用vmstat 1 120)的捕获。 我们在每次负载变化和测量之间等待15分钟,以确保系统在新负载周围稳定并且负载平均数更新:

50%的生产服务器工作负载: http : //pastebin.com/GE2kGLkk

34%的生产服务器工作负载: http : //pastebin.com/V2PWq8CG

生产服务器工作量的25%: http : //pastebin.com/0pxxK0Fu

随着负载的减少,CPU使用率似乎会降低,但不是在非常激烈的水平上(从50%变为25%并不是CPU使用率减少50%)。 负载平均值似乎与工作负载量无关。

还有一个问题:鉴于我们的测试服务器也是一个虚拟机,其CPU测量是否会受到在同一主机上运行的其他虚拟机的影响(使上述测量无用)?

更新2以三个部分附加线程的快照(pastebin限制)

第1部分: http : //pastebin.com/DvNzkB5z

第2部分: http : //pastebin.com/72sC00rc

第3部分: http : //pastebin.com/YTG9hgF5

在我看来问题是100个CPU绑定线程比什么都重要。 3000线程池基本上是一个红色的鲱鱼,因为空闲线程不会消耗太多任何东西。 I / O线程可能在“大部分”时间内处于hibernate状态,因为I / O是在计算机操作方面的地质时间尺度上测量的。

你没有提到100个CPU线程正在做什么,或者它们持续多长时间,但是如果你想减慢计算机的速度,专门设置100个“运行直到时间片表示停止”的线程肯定会这样做。 因为您有100个“随时可以运行”,所以机器将按照调度程序允许的速度进行上下文切换。 空闲时间几乎为零。 上下文切换会产生影响,因为您经常这样做。 由于CPU线程(可能)消耗大部分CPU时间,因此您的I / O“绑定”线程将在运行队列中等待的时间比等待I / O的时间长。 因此,更多的进程正在等待(I / O进程更频繁地拯救,因为它们很快就会遇到I / O障碍,这会导致下一个进程无效)。

毫无疑问,这里和那里都有调整以提高效率,但100个CPU线程是100个CPU线程。 你可以做的不多。

我认为你的约束是不合理的。 基本上你说的是:

1.I can't change anything 2.I can't measure anything 

你能猜一下我的问题是什么吗?

对此的真正答案是,您需要将适当的分析器连接到应用程序,并且需要将所看到的内容与CPU使用率,磁盘/网络I / O和内存相关联。

记住性能调优的80/20规则。 80%将来自调整您的应用程序。 对于一个VM实例,您可能只有太多的负载,并且可能是时候考虑通过为机器提供更多资源来水平或垂直扩展的解决方案。 可能是30亿JVM设置中的任何一个都不符合您的应用程序的执行细节。

我假设3000线程池来自着名的更multithreading=更多并发=更多的性能理论。 真正的答案是调整更改不值得,除非您在更改之前/之后测量吞吐量和响应时间并比较结果。

如果您无法进行配置,我建议您进行一两次线程转储并查看您的线程正在做什么。 您的应用无需停止执行此操作:

  1. http://docs.oracle.com/javase/6/docs/technotes/guides/visualvm/threads.html
  2. http://java.net/projects/tda/
  3. http://java.sys-con.com/node/1611555

那么 – 我们可以排除上下文切换或太multithreading作为问题吗?

我认为你担心捶打是有道理的。 在2 CPU VMware实例上具有3000个线程(700多个并发操作)的线程池当然看起来像是一个可能导致上下文切换过载和性能问题的问题。 尽管确定正确的数字会很困难并且可能会使用大量的反复试验,但限制线程数可以提高性能。

我们需要一些问题的证据。

我不确定最好的回答方法,但这里有一些想法:

  • 观察VM OS和JVM的平均负载。 如果您看到高负载值(20+),那么这表明运行队列中有太多东西。
  • 是否无法模拟测试环境中的负载,因此您可以使用线程池编号? 如果在池大小为X的测试环境中运行模拟负载,然后使用X / 2运行,则应该能够确定最佳值。
  • 你能比较一天的高负荷时间和一天的低负荷时间吗? 您能否在这些时间内绘制对延迟的响应数量,以确定您是否可以在颠簸方面看到一个临界点?
  • 如果您可以模拟负载,那么请确保您不仅仅是根据“消防水管饮料”方法进行测试。 您需要可以上下拨动的模拟负载。 从10%开始并减慢增加模拟负载,同时观察吞吐量和延迟。 您应该能够通过观察吞吐量变平或以其他方式偏转来查看临界点。

通常,线程中的上下文切换在计算上非常便宜,但是当它涉及这么multithreading时……你就是无法知道。 你说升级到Java 1.6 EE是不可能的,但是有些硬件升级呢? 它可能会提供快速修复,不应该那么昂贵……

例如,在类似的机器上运行一个分析器。

  • 尝试更新版本的Java 6或7.(它可能没有区别,在这种情况下不要打扰升级生产)
  • 试试Centos 6.x.
  • 尽量不要使用VMware。
  • 尝试减少线程数量。 你只有8个核心。

你们很多人发现上述选项中的所有选项都没有区别,但是在你拥有一个系统之前你不会知道你可以使用已知/可重复的工作负载进行测试。