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

时间:2015-03-19 10:33:48

标签: java linux multithreading

我们已经对我们的Java Web应用程序进行了负载测试,并观察了50个用户的高CPU使用率(这似乎不太实用)。 CPU上升超过80%。在使用java飞行记录(JFR)对其进行分析时,我们发现上下文切换速率为每秒8400(如java任务控制中的热线程选项卡中所示)。分析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 个答案:

答案 0 :(得分: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

答案 1 :(得分: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)

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