【问题标题】:JBoss CPU utilization issueJBoss CPU 利用率问题
【发布时间】:2011-06-13 12:44:31
【问题描述】:

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

【问题讨论】:

    标签: performance jboss cpu-usage josso


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 有没有可能是我的请求太重以至于它一直在阅读它们。而且我的 apache 和 jboss 实例在同一个物理框中。
    • 如果您继续进行堆栈转储,您会看到比socketRead0更多的活动@ jboss 至少至少还有其他东西。残酷的事实是,您需要首先查看应用程序所在的线程,jboss 和 apache 以及 jboss 在授权方案中并没有真正增加巨大的 CPU 开销。
    • 通常我希望等待线程处于 WAITING 状态,然后在 Tomcat(或 JBoss)等待org.apache.tomcat.util.net.JIoEndpoint$Worker 的情况下。我见过这样的情况,其中一个 AJP 守护线程也“卡”在 socketRead0 中,状态为 RUNNABLE,而所有其他线程都处于上述 WAITING 状态。
    • 再次感谢大家。我看到我所有的 socket.read0() 总是可运行的。而且我的 lbmethod 在 worker.properties 中是 S。另外我们正在使用 JoSSo 进行身份验证。当我们运行负载测试我们发现,即使发生注销,利用率也不会下降。对此有任何想法。
    • 您可以暂时切换到使用 mod_proxy/mod_proxy_http 来替换 mod_jk 并连接到 jboss 的 http 连接器,如果 CPU 使用率低得多,那么 mod_jk/AJP 设置确实存在问题跨度>
    【解决方案2】:

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

    问题

    JBoss Web 的 (Tomcat) server.xml AJP sn-p:

    <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 VM)以清除所有 挂线程;特别是如果你缺乏适当的超时 实施。

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

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

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

    你能做什么?

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

    JBoss端

    server.xml 的主要关注点是设置 connectionTimeout 它设置底层套接字的 SO_TIMEOUT。所以当一个连接在 Tomcat 在指定的时间内没有请求 connectionTimeout,然后连接断开。这是必要的 因为如果连接在一段时间内没有被使用 那么有可能在 mod_jk 端半关闭。

    如果连接未关闭,则会出现线程膨胀 随着时间的推移,这可能会达到 Tomcat 中的 maxThreads 计数,然后 Tomcat 将 无法接受任何新连接。一个连接超时 600000(10 分钟)是一个很好的开始数字。可能有 连接回收速度不够快的情况, 在这种情况下,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>
    

    Apache 端

    worker.properties 文件

    查看 cmets 内联。

    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 用于探测连接 errors 和 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。这并不总是 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 是否也用于其他模块,尤其是在 资源泄露案例。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-11-22
      • 1970-01-01
      • 2013-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多