3

我正在使用 JBoss AS 4.2.3 和 seam 框架。我的 CPU 使用率随着用户数量的增加而增加,仅 80 个用户就达到了 99%。我们还将 Hibernate、EJB3 和 Apache 与 mod_jk 一起用于负载平衡。

当我进行线程转储时,所有可运行线程都在执行相同的活动,并带有以下跟踪:

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 利用率仍然与处于相同状态的线程相同。

4

2 回答 2

1

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

此时,您确实需要通过分析器运行您的应用程序。

如果您无法在系统上运行分析器(即,它是一个生产机器),那么下一个最好的方法是每隔几秒钟开始进行许多堆栈转储,然后手动匹配线程 ID。您需要查找正在运行您的代码并且在转储之间似乎没有变化的线程。

这是一项非常繁琐的任务,并且并不总是能得到明确的结果,但是如果没有分析器或某种仪器,您将无法找到所有 CPU 的去向。

于 2011-06-13T13:00:57.417 回答
0

检查 Apache 和 Jboss 之间的 AJP 配置,如https://developer.jboss.org/wiki/OptimalModjk12Configuration中所述

问题

JBoss Web 的 (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 中没有设置连接限制。

但是这么多线程可能来自另一个来源。如此处所述:

挂起的 Socket.read() 最常见的情况是处理时间过长或远程服务提供商的状态不佳。这意味着您需要立即与服务提供商支持团队沟通,以确认他们的系统是否面临某些减速情况。

一旦远程服务提供商系统问题得到解决,您的应用程序服务器线程应该被释放,但通常您需要重新启动服务器实例(Java VM)以清除所有挂起的线程;特别是如果您缺乏适当的超时实现。

其他不太常见的原因包括:

  • 巨大的响应数据导致读取/使用套接字输入流的时间增加,例如非常大的 XML 数据。这可以通过分析响应数据的大小轻松证明
  • 网络延迟导致从服务提供商到 Java EE 生产系统的数据传输时间增加。这可以通过在生产服务器和服务提供商之间运行一些网络嗅探器来证明,并确定任何主要的延迟/延迟问题

无论您的问题是什么,首先要做的是检查您的超时配置!

你可以做什么?

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

JBoss端

server.xml的主要关注点是设置连接超时,它设置底层套接字的 SO_TIMEOUT。因此,当 Tomcat 中的连接在 connectionTimeout 指定的时间内没有请求时,连接就会断开。这是必要的,因为如果连接在一段时间内没有使用,那么它有可能在 mod_jk 端处于半关闭状态。

如果连接未关闭,则会出现线程膨胀,随着时间的推移会达到 Tomcat 中的 maxThreads 计数,然后 Tomcat 将无法接受任何新连接。600000(10 分钟)的 connectionTimeout 是一个很好的开始数字。可能存在连接回收速度不够快的情况,在这种情况下,connectionTimeout 可以降低到 60000 或 1 分钟。

在 Tomcat 中设置 connectionTimeout 时,mod_jk 还应该设置 connect_timeout/prepost_timeout,这样可以检测到 Tomcat 连接已关闭并防止重试请求。

maxThreads 的推荐值是每个 CPU 200,所以这里我们假设服务器是单核机器。如果它是四核,我们可以将该值推至 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 中的连接将同时关闭,防止连接半关闭。

阿帕奇配置

请注意,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。这并不总是 100% 准确,因此您还应该查看 /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 正在使用 worker,它是

<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 是否也用于其他模块,尤其是在资源泄漏的情况下。

在链接中,您可以找到另一种配置以进一步优化此方案。

于 2015-10-25T13:24:22.207 回答