经过一段时间后,Tomcat7卡住了

时间:2016-12-13 10:20:43

标签: java hibernate tomcat nginx tomcat7

我通过Hibernate 4.3和JPA 2.1使用tomcat 7.0.52 servlet服务器和postgresql数据库。

Nginx通过端口8080将所有对服务器的请求代理到tomcat服务器的端口8888。

服务器每秒大约有200个请求。几个小时后,它停止响应请求。我无法访问tomcat7管理器页面,因此无法访问servlet上下文。它始终响应请求超时错误。但是服务器仍在工作,我的服务仍然有效,并且可以访问数据库。

卡住我在tomcat7上的CPU使用率为0.04-0.08%,在postgresql上的CPU使用率为0.01-0.02%。相比之下,tomcat7上的CPU使用率为3-4%,而正常工作时postgresql的CPU使用率为12-14%。

重启tomcat7服务器后再次正常工作。

我认为数据库没有问题,postgresql-9.3-main.log为空但启用了日志记录。当我在psql中做错事时,我看到了它。

我认为OutOfMemory或任何其他异常没有问题,因为在tomcat7 catalina.out和localhost.YYYY-MM-DD.log的所有日志文件中没有任何异常和错误。

我认为nginx没有问题,因为对其他端口和网站的所有请求都工作正常。

我认为内存泄漏没有问题,JAVA总是消耗大约700-800 MB的内存,并且在卡住时没有任何峰值。

我用Google搜索了类似的问题,但这并没有帮助我。

当我将acceptorThreadCount从1更改为2时,服务器卡住的速度要快得多。

看起来tomcat7服务器接受连接时出现了问题。 我没有任何想法,我错过了。

JVM选项:

JAVA_OPTS="-Xms1024m -Xmx2048m -XX:MaxPermSize=256m"

Tomcat7版本信息:

Server version: Apache Tomcat/7.0.52 (Ubuntu)
Server built:   Jul 24 2014 08:38:51
Server number:  7.0.52.0
OS Name:        Linux
OS Version:     3.13.0-53-generic
Architecture:   amd64
JVM Version:    1.7.0_79-b14
JVM Vendor:     Oracle Corporation

Nginx配置文件:

worker_rlimit_nofile 8192;
worker_processes 4;
timer_resolution 100ms;
worker_priority -5;

pid /run/nginx.pid;

events {
    worker_connections 2048;
    use epoll;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    output_buffers 2 512k;
    client_max_body_size 150M;

    gzip on;
    gzip_min_length 1100;
    gzip_buffers 64 8k; 
    gzip_comp_level 3;
    gzip_disable "msie6";
    gzip_http_version 1.1;
    gzip_proxied any;
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    keepalive_timeout 30;
    server_tokens off;
    reset_timedout_connection on;
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    types_hash_max_size 2048;
    server_names_hash_bucket_size 64;
    server_names_hash_max_size 2056;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
    include blockips.conf;
}

Nginx服务器配置:

server {
    listen 8080;
    server_name <my_ip>;

    proxy_headers_hash_max_size 512;
    proxy_headers_hash_bucket_size 64;

    location / {
        proxy_set_header X-Forwarded-For $http_x_real_ip;
        #proxy_set_header X-NginX-Proxy true;

        proxy_pass         http://127.0.0.1:8888/; 
        proxy_redirect     off;
    }
}

连接器配置:

port="8888" 
protocol="org.apache.coyote.http11.Http11NioProtocol"
connectionTimeout="20000"
acceptorThreadCount="1"
maxThreads="500"
URIEncoding="UTF-8"
redirectPort="8443"

提前谢谢。

更新

问题解决了。我在这里找到了正确的解决方案https://stackoverflow.com/a/3731978/7289901

hibernate配置错误,因为idle_test_periods高于超时。在将这些变量修复为正确的值后,服务器变得非常稳定。

更新2

完整的hibernate cofig让我找出问题的原因:

<property name="hibernate.c3p0.acquire_increment">3</property>
<property name="hibernate.c3p0.acquireRetryAttempts">3</property>
<property name="hibernate.c3p0.acquireRetryDelay">250</property>
<property name="hibernate.c3p0.idle_test_period">10</property>
<property name="hibernate.c3p0.min_size">0</property>
<property name="hibernate.c3p0.max_size">50</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.timeout">30</property>
<property name="hibernate.c3p0.checkoutTimeout">500</property>
<property name="hibernate.c3p0.debugUnreturnedConnectionStackTraces">true</property>
<property name="hibernate.c3p0.unreturnedConnectionTimeout">30</property>
<property name="hibernate.c3p0.numHelperThreads">5</property>

1 个答案:

答案 0 :(得分:0)

我最初的猜测是你的JPA代码出了问题。 从Tomcat和DB开始,CPU都很低,最终在Tomcat上占3-4%,在DB服务器上占12-14%。

如果您的Tomcat应用程序是无状态的,那么扩展几乎是线性的,即使您在HttpSession中存储数据,在开始集群Tomcat之前也几乎没有开销。

如果您不执行全表扫描,但具有适当的索引,则DB也可以很好地扩展。也许您应该在postgresql(log_min_duration_statement属性)上启用慢速查询日志记录,以查看是否存在具有长运行时的单个查询。

如果您无法与Tomcat管理器连接,可能是因为使用了所有http接受器。但是您仍然可以使用JVisualVM进行连接。 JViaualVM有一个CPU采样器,如果你启动它,你应该能够看到花费的时间。这里的一个问题是你不能只看CPU时间(因为大部分CPU用在数据库上),如果你看一下自己的时间,调用堆栈中的每一个前一步都会比你的代码高一些(而tomcat和spring通常会添加20个堆栈帧)。

您可以尝试进行线程转储,并检查tomcats http线程正在做什么(这基本上就是CPU采样器所做的事情),因此您可以看到它被卡住的位置。

CPU采样和线程转储应该为您提供关于您的工作重点的想法。我的猜测是它与JPA有关。

可以使用JPA编写代码,以非常糟糕的方式使用数据库。通常,延迟加载的集合是一个很好的起点。如果您有ER模型 公司&gt; -Employee&gt; -phone(1-N,1-N)并且您想要打印公司中所有员工的电话号码,您可以从公司开始并遍历员工集合并通过电话循环每个员工数字。这将导致1 + N个查询,因为您需要一个查询来加载员工,并且每个员工都需要查询来加载电话号码。更好的解决方案是使用提取连接查询选择数据,因此数据库只执行一次查询,在一次操作中加载所有员工和电话号码。

另一个常见错误是将数据添加到延迟加载的集合中,因为这会导致JPA首先加载集合中的所有数据。

由于您使用的是Spring,因此您的实体管理器可能是托管的(并且是事务范围的),因此您可能在持久性上下文中没有数据累积问题。

如果您查询的是只读的,您应该检查您的JPA提供程序,看看是否有可以对此进行优化的@QueryHint。默认情况下,JPA必须保留加载到持久化上下文中的每个对象的副本,因此它可以检查在提交事务时是否进行了任何修改,此过程可能需要一些时间(并且对于只读查询没有任何用处)。

您可以为JPA启用查询日志记录,但它往往会产生大量输出。

希望您找到来源。