为什么我的Opteron内核每个只能运行75%的容量? (25%CPU闲置)

问题描述:

我们刚刚交付了128Gb的功能强大的32核AMD Opteron服务器。我们有2个6272 CPU和16个内核。我们正在30个线程上运行一个长期运行的java任务。我们为Linux和Java启用了NUMA优化。我们的Java线程主要使用该线程专用的对象,有时会读取其他线程将读取的内存,并且非常偶尔会写入或锁定共享对象。为什么我的Opteron内核每个只能运行75%的容量? (25%CPU闲置)

我们无法解释为什么CPU内核空闲25%。下面是“顶”转储:

 
top - 23:06:38 up 1 day, 23 min, 3 users, load average: 10.84, 10.27, 9.62 
Tasks: 676 total, 1 running, 675 sleeping, 0 stopped, 0 zombie 
Cpu(s): 64.5%us, 1.3%sy, 0.0%ni, 32.9%id, 1.3%wa, 0.0%hi, 0.0%si, 0.0%st 
Mem: 132138168k total, 131652664k used, 485504k free, 92340k buffers 
Swap: 5701624k total, 230252k used, 5471372k free, 13444344k cached 
... 
top - 22:37:39 up 23:54, 3 users, load average: 7.83, 8.70, 9.27 
Tasks: 678 total, 1 running, 677 sleeping, 0 stopped, 0 zombie 
Cpu0 : 75.8%us, 2.0%sy, 0.0%ni, 22.2%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu1 : 77.2%us, 1.3%sy, 0.0%ni, 21.5%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu2 : 77.3%us, 1.0%sy, 0.0%ni, 21.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu3 : 77.8%us, 1.0%sy, 0.0%ni, 21.2%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu4 : 76.9%us, 2.0%sy, 0.0%ni, 21.1%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu5 : 76.3%us, 2.0%sy, 0.0%ni, 21.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu6 : 12.6%us, 3.0%sy, 0.0%ni, 84.4%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu7 : 8.6%us, 2.0%sy, 0.0%ni, 89.4%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu8 : 77.0%us, 2.0%sy, 0.0%ni, 21.1%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu9 : 77.0%us, 2.0%sy, 0.0%ni, 21.1%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu10 : 77.6%us, 1.7%sy, 0.0%ni, 20.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu11 : 75.7%us, 2.0%sy, 0.0%ni, 21.4%id, 1.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu12 : 76.6%us, 2.3%sy, 0.0%ni, 21.1%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu13 : 76.6%us, 2.3%sy, 0.0%ni, 21.1%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu14 : 76.2%us, 2.6%sy, 0.0%ni, 15.9%id, 5.3%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu15 : 76.6%us, 2.0%sy, 0.0%ni, 21.5%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu16 : 73.6%us, 2.6%sy, 0.0%ni, 23.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu17 : 74.5%us, 2.3%sy, 0.0%ni, 23.2%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu18 : 73.9%us, 2.3%sy, 0.0%ni, 23.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu19 : 72.9%us, 2.6%sy, 0.0%ni, 24.4%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu20 : 72.8%us, 2.6%sy, 0.0%ni, 24.5%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu21 : 72.7%us, 2.3%sy, 0.0%ni, 25.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu22 : 72.5%us, 2.6%sy, 0.0%ni, 24.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu23 : 73.0%us, 2.3%sy, 0.0%ni, 24.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu24 : 74.7%us, 2.7%sy, 0.0%ni, 22.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu25 : 74.5%us, 2.6%sy, 0.0%ni, 22.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu26 : 73.7%us, 2.0%sy, 0.0%ni, 24.3%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu27 : 74.1%us, 2.3%sy, 0.0%ni, 23.6%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu28 : 74.1%us, 2.3%sy, 0.0%ni, 23.6%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu29 : 74.0%us, 2.0%sy, 0.0%ni, 24.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu30 : 73.2%us, 2.3%sy, 0.0%ni, 24.5%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Cpu31 : 73.1%us, 2.0%sy, 0.0%ni, 24.9%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Mem: 132138168k total, 131711704k used, 426464k free, 88336k buffers 
Swap: 5701624k total, 229572k used, 5472052k free, 13745596k cached 

    PID USER  PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 
13865 root  20 0 122g 112g 3.1g S 2334.3 89.6 20726:49 java 
27139 jayen  20 0 15428 1728 952 S 2.6 0.0 0:04.21 top 
27161 sysadmin 20 0 15428 1712 940 R 1.0 0.0 0:00.28 top 
    33 root  20 0  0 0 0 S 0.3 0.0 0:06.24 ksoftirqd/7 
    131 root  20 0  0 0 0 S 0.3 0.0 0:09.52 events/0 
1858 root  20 0  0 0 0 S 0.3 0.0 1:35.14 kondemand/0 

Java堆栈的转储证实,没有线程都在附近的任何地方,其中用于锁定几个地方,也不是任何磁盘或网络附近的任何地方I/O操作。

我很难找到关于“空闲”与“等待”意味着什么“顶部”的明确解释,但我得到的印象是“空闲”意味着“没有更多需要运行的线程”,但这并不意味着“在我们的情况下没有意义。我们正在使用“Executors.newFixedThreadPool(30)”。有大量的任务待处理,每个任务持续10秒左右。

我怀疑这个解释需要很好的理解NUMA。当CPU等待非本地访问时,“空闲”状态是什么?如果不是,那么解释是什么?

+0

是否可以运行缩减版本的应用程序并通过类似Java VisualVM的东西查看它?如果您使用应用程序启动它,它的重量足够轻,您可以观察线程运行的时间以及阻塞的内容。 – pickypg

+0

我怀疑你有一些延迟瓶颈,尽管你有限的使用锁。您是否尝试过在应用程序中运行CPU和内存分析器,以查看是否有阻塞操作出现? –

+0

Peter,我们一直在转储堆栈跟踪信号,并且不停止程序的运行,这表明没有任何线程在使用锁定的几个地方附近。 –

这可能是一些事情:

  • 这可能是在访问共享数据的线程之间的争用。这可能会采取锁竞争的形式,或者由于读或写障碍导致的额外内存流量,尽管后者不太可能产生这些症状。

  • 您正在泄漏工作线程;例如他们偶尔会死亡,不会被取代。

  • 执行者本身可能存在一个瓶颈;例如它可能没有足够快速响应任务,以完成下一个任务的完成任务。

  • 瓶颈可能是垃圾收集器,特别是如果您没有启用并行收集。


This page关于Java的NUMA增强会谈,并提到了NUMA感知GC开关。试试看。还请查看该页面上的其他GC调整建议。

这个问题解释了过程状态:In linux, what do all the values in the "top" command mean?

我认为处理器总结中“wa”和“idle”时间之间的差别是“wa”意味着处理器具有处于“D”状态的线程;即等待磁盘I/O。相比之下,所有线程以“S”状态等待的处理器将被计为“空闲”。 (从这个角度看,等待锁的线程将处于S状态。)

您也可以尝试top -H,它会单独显示线程。

+0

谢谢,但这4个建议都没有提出。 (我可以详细说明你是否想要)。您指出我关于“顶部”中的值的这个问题没有定义“等待”或“空闲”或解释它们是同义词所描述的哪些状态。 –

+0

@TimCooper - 1)直到你确定问题到底是什么,我才看不出如何消除所有这些可能性。 2)我没有说。该链接解释了流程状态......您需要了解以下段落。 –

+0

关于过程状态的解释的道歉。关于4个想法:(1)是一种可能性,尽管堆栈跟踪在我们使用锁的几个地方附近没有显示任何内容,所以(1b),即内存通信是最有可能的。 (2)堆栈跟踪显示所有30个工作线程完好无损地深入进程; (3)我们使用标准的Java固定线程执行程序池; (4)好点 - 我需要检查关于并行垃圾收集。但我希望并行垃圾收集能够使用所有CPU内核来满负荷......? –