2011-06-13 162 views
3

我正在使用JBoss AS 4.2.3以及seam框架。我的CPU使用率随着用户数量的增加而增加,仅有80个用户使用率达到99%。我们还使用Hibernate,EJB3和Apache与mod_jk进行负载平衡。JBoss CPU使用率问题

当我拿着线程转储所有可运行的线程正在做以下的跟踪同一个活动:

at java.net.SocketInputStream.socketRead0(Native Method) 
at java.net.SocketInputStream.read(SocketInputStream.java:129) 
at org.apache.coyote.ajp.AjpProcessor.read(AjpProcessor.java:1012) 
at org.apache.coyote.ajp.AjpProcessor.readMessage(AjpProcessor.java:1091) 
at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:384) 
at org.apache.coyote.ajp.AjpProtocol$AjpConnectionHandler.process(AjpProtocol.java:366) 
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446) 
at java.lang.Thread.run(Thread.java:662) 

我无法与堆栈跟踪来解释这一点。此外,我发现,即使用户已注销,CPU利用率仍会继续与处于相同状态的线程相同。

回答

1

这些线程试图从Socket连接读取。在这种情况下,他们正在等待下一个请求从Apache的mod_jk发送到服务器。这很正常,它们可能不是你CPU使用率的原因。

在这一点上,你真的需要去通过一个分析器来运行你的应用程序。

如果你无法在系统上运行一个分析器(例如它是一个生产盒),下一个最好的事情是开始每隔几秒钟进行一次堆栈转储,然后通过手工匹配线程ID。您需要查找正在运行代码的线程,并且在转储之间似乎没有更改。

这是一项非常乏味的任务,并不总是会得到清晰的结果,但是如果没有探查器或某种仪器,您将无法找到所有CPU将要发生的位置。

+0

是否有可能我的请求太重以至于始终读取它们。另外,我的apache和jboss实例位于相同的物理盒子中。 – Dwarakanath 2011-06-13 13:10:34

+0

如果你继续采用堆栈转储,你会看到更多的活动,而不仅仅是'socketRead0' jboss至少会有其他的东西。最残酷的事实是,首先需要关注应用程序中的线程,jboss和apache以及jboss的线程并不会真正增加事物授权方案中的巨大CPU开销。 – 2011-06-13 13:21:54

+1

通常我会期待等待的线程处于状态WAITING,然后是Tomcat(或JBoss)等待'org.apache.tomcat.util.net.JIoEndpoint $ Worker'。我曾见过其中一个AJP deamon线程在状态为RUNNABLE的socketRead0中“卡住”的情况,其中所有其他状态都处于上述WAITING状态。 – 2011-06-13 13:24:00

0

审查的Apache和JBoss之间的AJP的配置,如https://developer.jboss.org/wiki/OptimalModjk12Configuration

问题

JBoss应用的(Tomcat)的server.xml中AJP描述片段:

<Connector port="8009" address="${jboss.bind.address}" protocol="AJP/1.3" 
     emptySessionPath="true" enableLookups="false" redirectPort="8443" ></Connector> Apache's httpd.conf: 

<IfModule prefork.c> 
StartServers  8 
MinSpareServers 5 
MaxSpareServers 20 
ServerLimit  256 
MaxClients  256 
MaxRequestsPerChild 4000 
</IfModule> 

以上配置,在负载下,可能会导致mod_jk非常慢,并且不响应,导致http错误,并导致半连接的 连接。出现这些问题的原因可能是因为没有指定用于照顾孤立连接的连接超时 ,没有在worker.properties中定义的 错误处理属性,也没有在Apache和Tomcat中设置 连接限制。

但是这么多的线程可能来自另一个来源。如上所述here

的悬挂Socket.read(最常见的情况)是一种高 处理时间或远程服务提供商的不健康状态。 这意味着您需要立即与服务提供商 联系支持团队,以确认他们的系统是否面临某些 减速条件。

你的一个应用服务器的线程应该被释放,一旦远程 服务提供商的系统问题得以解决,但往往你会 需要重新启动服务器实例(Java虚拟机),以清除所有 挂线程;特别是如果你缺乏适当的超时执行 。

其他较少见的原因包括:使增加经过时间

  • 巨大响应数据读/消耗的插座的InputStream例如如非常大的XML数据。通过分析响应数据的大小可以很容易地证明这可以是
  • 网络延迟导致从服务提供商到Java EE生产系统的数据传输所花费的时间增加。这可以 运行您的生产 服务器之间和服务提供商的一些网络嗅探器,并确定任何重大的滞后/延迟 问题

无论是你的问题,要做的第一件事就是检查你的超时被证明组态!

你可以做什么?

你需要为Jboss和Apache做一些配置。

的JBoss侧

的server.xml主要关心的是设定为ConnectionTimeout 它设置底层套接字的SO_TIMEOUT。因此,当 中的连接在012xxconnectionTimeout指定的时间内没有请求时,则连接将中断。这是必要的 ,因为如果连接没有被用于特定时间段 时间那么它有可能在mod_jk结束时是半关闭的。

如果连接没有关闭,将会出现线程膨胀 ,这会随着时间的流逝而击中Tomcat中的maxThreads计数,那么Tomcat将不能接受任何新的连接。连接超时 600000(10分钟)是一个很好的开始。可能存在 这种情况,其中连接没有被足够快地回收,在这种情况下, 可以将connectionTimeout降低到60000分钟或10分钟。

在Tomcat中设置connectionTimeout时,mod_jk也应该设置为 connect_timeout/prepost_timeout,它允许检测到Tomcat连接已关闭并阻止重试请求。我们假设 服务器是单核心机器。如果它是四核,那么我们 可以将该值推到800,并且更多取决于RAM和其他 机器规格。

<Connector port="8009" 
      address="${jboss.bind.address}" 
      emptySessionPath="true" 
      enableLookups="false" 
      redirectPort="8443" 
      protocol="AJP/1.3" 
      maxThreads="200" 
      connectionTimeout="600000"></Connector> 

阿帕奇侧

worker.properties文件

见注释行内。

worker.list=loadbalancer,status 

worker.template.port=8009 
worker.template.type=ajp13 
worker.template.lbfactor=1 
#ping_timeout was introduced in 1.2.27 
worker.template.ping_timeout=1000 
#ping_mode was introduced in 1.2.27, if not 
#using 1.2.27 please specify connect_timeout=10000 
#and prepost_timeout=10000 as an alternative 
worker.template.ping_mode=A 
worker.template.socket_timeout=10 
#It is not necessary to specify connection_pool_timeout if you are running the worker mpm 
worker.template.connection_pool_timeout=600 

#Referencing the template worker properties makes the workers.properties shorter and more concise 
worker.node1.reference=worker.template 
worker.node1.host=192.168.1.2 

worker.node2.reference=worker.template 
worker.node2.host=192.168.1.3 

worker.loadbalancer.type=lb 
worker.loadbalancer.balance_workers=node1,node2 
worker.loadbalancer.sticky_session=True 

worker.status.type=status 

在上述workers.properties的关键点是我们增加了限制 为mod_jk的使得连接。使用基本配置时,套接字 超时默认为无限。其他重要属性是 ping_mode和ping_timeout,它们处理探测连接的错误和connection_pool_timeout,必须设置为 当使用prefork mpm时,server.xml的connectionTimeout。当这两个值相同时,连接在x 时间内处于非活动状态后,mod_jk和Tomcat中的连接将同时关闭,并在 处关闭,从而阻止半关闭连接。

Apache配置

记下的AJP连接maxThreads应 在Apache的httpd.conf设置的MaxClients一致。 MaxClients需要在Apache的正确模块中设置为 。

这可以通过运行httpd -V确定:

# httpd -V 

Server version: Apache/2.2.3 
Server built: Sep 11 2006 09:43:05 
Server's Module Magic Number: 20051115:3 
Server loaded: APR 1.2.7, APR-Util 1.2.8 
Compiled using: APR 1.2.7, APR-Util 1.2.7 
Architecture: 32-bit 
Server MPM:  Prefork 
    threaded:  no 
    forked:  yes (variable process count) 
Server compiled with.... 
-D APACHE_MPM_DIR="server/mpm/prefork" 
-D APR_HAS_SENDFILE 
-D APR_HAS_MMAP 
-D APR_HAVE_IPV6 (IPv4-mapped addresses enabled) 
-D APR_USE_SYSVSEM_SERIALIZE 
-D APR_USE_PTHREAD_SERIALIZE 
-D SINGLE_LISTEN_UNSERIALIZED_ACCEPT 
-D APR_HAS_OTHER_CHILD 
-D AP_HAVE_RELIABLE_PIPED_LOGS 
-D DYNAMIC_MODULE_LIMIT=128 
-D HTTPD_ROOT="/etc/httpd" 
-D SUEXEC_BIN="/usr/sbin/suexec" 
-D DEFAULT_PIDLOG="logs/httpd.pid" 
-D DEFAULT_SCOREBOARD="logs/apache_runtime_status" 
-D DEFAULT_LOCKFILE="logs/accept.lock" 
-D DEFAULT_ERRORLOG="logs/error_log" 
-D AP_TYPES_CONFIG_FILE="conf/mime.types" 
-D SERVER_CONFIG_FILE="conf/httpd.conf" 

它告诉我的服务器MPM为prefork的。这并不总是准确的,因此您还应该查看/ etc/sysconfig/httpd的输出为 ,看下面的行是否存在:HTTPD =/usr/sbin/httpd.worker。如果 它被注释掉你正在运行prefork,否则如果没有注释 工人。

的httpd.conf:

<IfModule prefork.c> 
StartServers  8 
MinSpareServers 5 
MaxSpareServers 20 
MaxClients  200 
MaxRequestsPerChild 0 
</IfModule> 

或者Apache是​​否使用工人,这是

<IfModule worker.c> 
StartServers   2 
MaxClients   200 
MinSpareThreads  25 
MaxSpareThreads  75 
ThreadsPerChild  25 
MaxRequestsPerChild 0 
</IfModule> 

MaxRequestsPerChild值0,这是建议值使用的mod_jk 作为时的mod_jk保持开放的持久连接。 上述配置中的关键值是MaxClients和MaxRequestsPerChild,其余的值保留为默认值。请注意,MaxRequestsPerChild 建议为0,但该值可能需要大于0 ,具体取决于Apache是​​否也用于其他模块,尤其是在 资源泄漏的情况下。

在链接中,您可以找到另一个配置来优化更多此场景。