检查 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 是否也用于其他模块,尤其是在资源泄漏的情况下。
在链接中,您可以找到另一种配置以进一步优化此方案。