Java Web应用程序的高线程上下文切换

5
我们一直在对Java Web应用进行负载测试,发现在50个用户下CPU使用率很高(这似乎不太实际)。CPU占用率高达80%以上。通过使用Java Flight Recording (JFR)进行性能分析,我们发现上下文切换率为每秒8400次(在Java Mission Control的Hot threads选项卡中可见)。通过分析jfr中的热线程,似乎观察到CPU使用率分布在应用程序线程之间,每个线程使用的CPU不到3%。
将用户负载增加到100、150或200个时,我们发现CPU占用率超过90%,吞吐量(每秒事务数)保持不变(在50个用户负载下可见),而响应时间超过了可接受的阈值值(3秒)。将用户负载减少到20个时,CPU使用率平均超过55%。显然,应用程序线程并未占用CPU,因为我们的应用程序不是CPU密集型应用程序。代码选项卡组下的热包选项卡通过显示大部分时间应用程序在执行数据库查询来证实这一点。
我们使用Glassfish 3.1.2.2作为应用服务器,其中最大线程池配置为100。我们的操作系统是Oracle Linux Server 6.4,Linux内核版本为2.6.39-400.214.4.el6uek.x86_64。我尝试执行Linux命令“watch -n0.5 pidstat -w -I -p”和“watch -n.5 grep ctxt /proc/ /status”来查看操作系统级别的自愿和非自愿线程上下文切换情况,但它们并没有给出任何结果。
怀疑高的上下文切换可能是导致CPU升高的原因,您是否有关于如何确认线程上下文切换是高CPU使用率的原因以及如果是原因的话,调整JVM或应用程序的指导方针?谢谢!
2个回答

1
你可以使用性能计数器来统计操作中上下文切换的次数。为此,请使用perf应用程序。
命令应该是perf stats -e cs <command>。这是一个例子:
[breno@debra ~]$ sudo perf stat  -e cs ls > /dev/null

Performance counter stats for 'ls':
   0    cs   (context switch)                                             

   0.001932855 seconds time elapsed

[breno@debra ~]$ sudo perf stat  -e cs ls -R > /dev/null

Performance counter stats for 'ls -R':

   3,130   cs (context switch)                                                        

   3.537120431 seconds time elapsed

0

我知道这是一个老问题,但是为了那些正在处理相同问题的人。
命令:pidstat -wt 3,将为您提供线程特定上下文切换的细节。 然后您可以对Java进程执行线程转储, 并查找您看到高上下文切换的线程号。(根据线程转储输出,您可能需要将线程号转换为十六进制)。 尽管我们仍然不确定核心问题是什么,因为具有最高上下文切换量的线程指向:

"NioBlockingSelector.BlockPoller-1" #37 daemon prio=5 os_prio=0 tid=0x00007f2b60b1f000 nid=0x1f48 runnable [0x00007f2b40af6000]
   java.lang.Thread.State: RUNNABLE
        at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
        at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
        at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
        at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
        - locked <0x0000000700ae6c78> (a sun.nio.ch.Util$3)
        - locked <0x0000000700ae6c68> (a java.util.Collections$UnmodifiableSet)
        - locked <0x0000000700ae6b30> (a sun.nio.ch.EPollSelectorImpl)
        at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
        at org.apache.tomcat.util.net.NioBlockingSelector$BlockPoller.run(NioBlockingSelector.java:298)

这是有道理的,因为它是一个线程选择器,但不确定如何从这里继续 :)


是的。由于这已经有一段时间了,我无法尝试它,但从上面的描述中,我无法确定它是否有帮助,因为所有线程的 CPU 使用率仅为 3%,而且大多数线程都在进行上下文切换。假设这是根本原因,下一步应该采取什么措施仍然未知。 - Andy Dufresne

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