Tomcat进程假死问题排查

目录
  • 1.网络
    • 1.1 检查nginx的网络情况
    • 1.2 检查tomcat的网络情况
  • 2.Jvm内存溢出
    • 2.1为什么会发生内存泄漏
    • 2.2快速定位问题
    • 2.3 jstack查看tomcat是否出现死锁
    • 2.4 jstat查看gc运行情况
    • 2.5 jmap获取内存快照
  • 3. jvm GC 时间过长,导致应用暂停
  • 4. load 太高,已经超出服务的极限
  • 5. 大量tcp 连接 TIME_WAIT
    • 5.2、保持和server的长连接:
    • 5.3、 proxy_set_header 配置注意事项
  • 6. tomcat长连接数超过最大连接数

1.网络

1.1 检查nginx的网络情况

更改nginx的配置,让该台nginx请求只转到本机器的出现问题的tomcat应用上面,在access.log里看是否有网络请求,结果可以查看到当前所有的网络请求,也就是说可以排除是网络的问题。

1.2 检查tomcat的网络情况

分析业务配置的tomcat访问日志xxxx.log上是否有日志访问记录,经过查询该台tomcat应用日志完全没有任何访问记录,由于我们的部署是本机的nginx转到本机的tomcat应用,所以可以排除不是网络问题。 到此基本可以断定网络没有问题,tomcat 本身出现了假死的情况。在tomcat的日志里有报过OutOfMemoryError的异常,所以可以肯定tomcat假死的原因是OOM

2.Jvm内存溢出

2.1为什么会发生内存泄漏

在我们学习Java的时候就知道它最为方便的地方就是我们不需要管理内存的分配和释放,一切由JVM自己来进行处理,当Java对象不再被应用时,等到堆内存不够用时JVM会进行GC处理, 清除这些对象占用的堆内存空间,但是如果对象一直被应用,那么JVM是无法对其进行GC处理的,那么我们创建新的对象时,JVM就没有办法从堆中获取足够的内存分配给此对象,这时就会导致OOM。 我们出现OOM原因,一般都是因为我们不断的往容器里存放对象,然而容器没有相应的大小限制或清除机制,这样就容易导致OOM。

2.2快速定位问题

当我们的应用服务器占用了过多内存的时候,我们怎么样才能快速的定位问题呢?要想快速定位问题,首先我们必需获取服务器JVM某时刻的内存快照。 Jdk里面提供了很多相应的命令比如:jstack,jstat,jmap,jps等等. 在出现问题后我们应该快速保留现场。

2.3 jstack查看tomcat是否出现死锁

可以观察到jvm中当前所有线程的运行情况和线程当前状态.

sudo jstack -F 进程ID

输出内容如下: 从上面的图我们可以看到tomcat进程里面没有死锁的情况,而且每个线程都处理等待的状态。这个时候我们可以telnet命令连上tomcat的端口查看tomcat进程是否有任务回应。这时发现tomcat没有任何回应可以证明tomcat应用已没有响应处理假死状态。

在thread dump中,要留意下面几种状态  死锁,
•  Deadlock(重点关注)  等待资源,
•  Waiting on condition(重点关注)
•  等待获取监视器,Waiting on monitor entry(重点关注)
•  阻塞,Blocked(重点关注)
•  执行中,Runnable
•  暂停,Suspended
•  对象等待中,Object.wait() 或 TIMED_WAITING
•  停止,Parked
 

2.4 jstat查看gc运行情况

2.5 jmap获取内存快照

Jdk自带的jmap可以获取内在某一时刻的快照

命令:

jmap -dump:format=b,file=heap.bin file:保存路径及文件名 pid:进程编号(windows通过任务管理器查看,linux通过ps aux查看)

dump文件可以通过MemoryAnalyzer分析查看,网址:http://www.eclipse.org/mat/,可以查看dump时对象数量,内存占用,线程情况等。

3. jvm GC 时间过长,导致应用暂停

查看gc.log回收时间,以下为例子:

7581088.402: [Full GC (System) 7581088.402: [CMS: 661091K->669762K(7340032K),
1.7206330 secs] 848607K->669762K(8238848K), [CMS Perm : 34999K->34976K(58372K)],
1.7209480 secs] [Times: user=1.72 sys=0.00, real=1.72 secs]

最近的一次full gc 显示,也不应该会暂停几分钟的情况,这种假死可能可以排除。

4. load 太高,已经超出服务的极限

使用top 命令查看资源使用情况,都在合理范围,排除。

5. 大量tcp 连接 TIME_WAIT

Linux:

使用 ss -s 命令查看 tcp 链接状态, 发现TIME_WAIT 1800+, 有点高,需要修改。

打开 sysctl.conf 文件,修改以下几个参数:

[root@web01 ~]# vim /etc/sysctl.conf

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_tw_recycle = 1

net.ipv4.tcp_timestamps = 1

net.ipv4.tcp_syncookies = 1

net.ipv4.tcp_fin_timeout = 30

开启tcp_tw_reuse 和 tcp_tw_recycle 需要timestamps的支持,而且这些配置一般不建议开启,但是对解决TIME_WAIT过多问题有效果。谨慎操作!!!

然后又发现,nginx 没有开启长连接。

当使用nginx作为反向代理时,为了支持长连接,需要做到两点:

  • 从client到nginx的连接是长连接
  • 从nginx到server的连接是长连接

Windows:

netstat -ano -p tcp

netstat -ano | find "ESTABLISHED"

5.1、保持和client的长连接:

[root@web01 ~]# vim /etc/sysctl.conf

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_tw_recycle = 1

net.ipv4.tcp_timestamps = 1

net.ipv4.tcp_syncookies = 1

net.ipv4.tcp_fin_timeout = 30

1)keepalive_timeout
语法:

keepalive_timeout timeout [header_timeout];

第一个参数:设置keep-alive客户端连接在服务器端保持开启的超时值(默认75s);值为0会禁用keep-alive客户端连接;第二个参数:可选、在响应的header域中设置一个值“Keep-Alive: timeout=time”;通常可以不用设置;

注:keepalive_timeout默认75s,一般情况下也够用,对于一些请求比较大的内部服务器通讯的场景,适当加大为120s或者300s;

2)keepalive_requests:

keepalive_requests指令用于设置一个keep-alive连接上可以服务的请求的最大数量,当最大请求数量达到时,连接被关闭。默认是100。这个参数的真实含义,是指一个keep alive建立之后,nginx就会为这个连接设置一个计数器,记录这个keep alive的长连接上已经接收并处理的客户端请求的数量。如果达到这个参数设置的最大值时,则nginx会强行关闭这个长连接,逼迫客户端不得不重新建立新的长连接。

大多数情况下当QPS(每秒请求数)不是很高时,默认值100凑合够用。但是,对于一些QPS比较高(比如超过10000QPS,甚至达到30000,50000甚至更高) 的场景,默认的100就显得太低。

简单计算一下,QPS=10000时,客户端每秒发送10000个请求(通常建立有多个长连接),每个连接只能最多跑100次请求,意味着平均每秒钟就会有100个长连接因此被nginx关闭。同样意味着为了保持QPS,客户端不得不每秒中重新新建100个连接。因此,就会发现有大量的TIME_WAIT的socket连接(即使此时keep alive已经在client和nginx之间生效)。因此对于QPS较高的场景,非常有必要加大这个参数,以避免出现大量连接被生成再抛弃的情况,减少TIME_WAIT。

5.2、保持和server的长连接:

nginx访问后端默认都是用的短连接(HTTP1.0)

为了让nginx和后端server(nginx称为upstream)之间保持长连接,location中有两个参数需要设置:

http {
    server {
        location /  {
            proxy_http_version 1.1;
            proxy_set_header Connection "";
        }
    }
}

5.3、 proxy_set_header 配置注意事项

在当前级别的配置中没有定义 proxy_set_header 指令时,这些指令从上级继承。
如果当前级别的配置中已经定义了 proxy_set_header 指令,在上级中定义的proxy_set_header 指令在当前级别都会失效。

举个例子:

http {
    ...
    proxy_http_version 1.1;
    proxy_set_header Host       $host;
    proxy_set_header Connection "";
    proxy_set_header X-Real-IP $remote_addr;

    upstream example.com_test {
        server 127.0.0.1:8080;

        keepalive 16;
    }

    server {
        server_name  example.com;

        location ^~ /test/ {
            proxy_set_header test      test;
            proxy_pass http://example.com_test;
        }
    }
}

这里后端服务器不能从 Header 中获取到 X-Real-IP。location ^~/test/ 中的proxy_set_header会覆盖上面的配置。

正确的做法,在location 中重复配置一遍:

http {
    ...
    proxy_http_version 1.1;
    proxy_set_header Host       $host;
    proxy_set_header Connection "";
    proxy_set_header X-Real-IP $remote_addr;

    upstream example.com_test {
        server 127.0.0.1:8080;

        keepalive 180;
    }

    server {
        server_name  example.com;

        location ^~ /test/ {
            proxy_set_header test      test;
            proxy_set_header Host       $host;
            proxy_set_header Connection "";
            proxy_set_header X-Real-IP $remote_addr;
            proxy_pass http://example.com_test;
        }
    }
}

6. tomcat长连接数超过最大连接数

发现tomcat 使用的是默认配置

tomcat默认最大连接数(线程数)200个,默认每一个连接的生命周期2小时(7200秒),tomcat使用http 1.1协议,而http1.1默认是长连接。tomcat接受处理完请求后,socket没有主动关闭,因此如果在2小时内,请求数超过200个,服务器就会出现上述假死现象。

解决办法:

(1)检查代码,及时断开socket

(2)修改tomcat配置文件,修改最大连接数(增大)

(3)修改linux的TCP超时时间(socket生命周期)限制

到此这篇关于Tomcat进程假死问题排查的文章就介绍到这了,更多相关Tomcat进程假死问题排查内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Tomcat进程占用CPU过高的解决方法

    目录 案例 上下文切换开销? 总结 CPU经常会成为系统性能的瓶颈,可能: 内存泄露导致频繁GC,进而引起CPU使用率过高 代码Bug创建了大量的线程,导致CPU频繁上下文切换 通常所说的CPU使用率过高,隐含着一个用来比较高与低的基准值,比如 JVM在峰值负载下的平均CPU利用率40% CPU使用率飙到80%就可认为不正常 JVM进程包含多个Java线程: 一些在等待工作 另一些则正在执行任务 最重要的是找到哪些线程在消耗CPU,通过线程栈定位到问题代码 如果没有找到个别线程的CPU使用率特别

  • Tomcat 发布程序使用cmd查看端口占用、相应进程、杀死进程等的命令

    如何查看程序占用的端口 一. 查看所有进程占用的端口 在开始-运行-cmd,输入:netstat –ano可以查看所有进程 二.查看占用指定端口的程序 当你在用tomcat发布程序时,经常会遇到端口被占用的情况,我们想知道是哪个程序或进程占用了端口,可以用该命令 netstat –ano|findstr "指定端口号" 二.查看占用指定端口的程序 当你在用tomcat发布程序时,经常会遇到端口被占用的情况,我们想知道是哪个程序或进程占用了端口,可以用该命令 netstat –ano|f

  • 记一次tomcat进程cpu占用过高的问题排查记录

    本文主要记录一次tomcat进程,因TCP连接过多导致CPU占用过高的问题排查记录. 问题描述 linux系统下,一个tomcat web服务的cpu占用率非常高,top显示结果超过200%.请求无法响应.反复重启依然同一个现象. 问题排查 1.获取进程信息 通过jdk提供的jps命令可以快速查出jvm进程, jps pid 2.查看jstack信息 jstack pid 发现存在大量log4j线程block,处于waiting lock状态 org.apache.log4j.Category.

  • 关于 Tomcat进程意外退出的问题解析

    节前某个部门的测试环境反馈tomcat会意外退出,我们到实际环境排查后发现不是jvm crash,日志里有进程销毁的记录,从pause到destory的整个过程: org.apache.coyote.AbstractProtocol pause Pausing ProtocolHandler org.apache.catalina.core.StandardService stopInternal Stopping service Catalina org.apache.coyote.Abstr

  • Tomcat进程假死问题排查

    目录 1.网络 1.1 检查nginx的网络情况 1.2 检查tomcat的网络情况 2.Jvm内存溢出 2.1为什么会发生内存泄漏 2.2快速定位问题 2.3 jstack查看tomcat是否出现死锁 2.4 jstat查看gc运行情况 2.5 jmap获取内存快照 3. jvm GC 时间过长,导致应用暂停 4. load 太高,已经超出服务的极限 5. 大量tcp 连接 TIME_WAIT 5.2.保持和server的长连接: 5.3. proxy_set_header 配置注意事项 6.

  • Java服务假死之生产事故的排查与优化问题

    目录 一.现象 二.排查 1.打印堆栈 2.查看socket连接 3.查看JVM基本信息 4.查看GC日志 5.分析dump文件 三.优化 四.总结 一.现象 在服务器上通过curl命令调用一个Java服务的查询接口,半天没有任何响应.关于该服务的基本功能如下: 1.该服务是一个后台刷新指示器的服务,即该服务会将用户需要的指示器数据提前计算好,放入redis中,当用户请求指示器数据时便从redis中获取: 2.指示器涉及到的模型数据更新时会发送消息到kafka,该服务监听kafka消息,收到消息

  • 详解PHP解决守护进程Redis假死

    目录 一.一个简单的守护进程示例 二.一个不再假死(伪活)的 Redis 常驻进程示例 一.一个简单的守护进程示例 <?php $redis = new \Redis(); $redis->connect('localhost', 6379); $redis->auth('xxxxx'); // Redis 密码如果没有设置为空字符串. $redis->select(1); $queueKey = 'redis_queue_services_key'; // 业务数据队列. $qu

  • Spring Boot假死诊断实战记录

    这两天遇到一个服务假死的问题,具体现象就是服务不再接收任何请求,客户端会抛出Broken Pipe. 检查系统状态 执行top,发现CPU和内存占用都不高,但是通过命令 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 发现有大量的CLOSE_WAIT端口占用,继续调用该服务的api,等待超时之后发现CLOSE_WAIT的数量也没有上升,也就是说服务几乎完全僵死. 检查JVM情况 怀疑可能是线程有死锁,决定先

  • 简单几招让你的电脑不再假死机

    死机,相信是很多朋友习以为常的事.一发现死机,我们通常都会直接热启动或按"Reset",但孰不知,有时电脑并未真正死机,只不过是处于一种假死的状态.按下数字键区的"Num Lock"键,如果指示灯有反应,则说明是假死机.那我们该如何处理真.假死机呢? 一.修改注册表,远离假死机困扰 很多假死机是由于运行的程序没有响应造成的.比如你在同一时间打开或启动的程序过多,导致系统资源消耗严重,就会出现程序停止响应的情况,这时我们可以按下"Ctrl+Alt+Del&q

  • C# WinForm程序处理后台繁忙导致前台控件假死现象解决方法

    特别是针对循环或timer处理中需要在窗体控件显示数据时,因后台处理过度繁忙而出现没刷新或者假死现象时,可以使用 复制代码 代码如下: Application.DoEvents(); Application.DoEvents()的作用 复制代码 代码如下: private void button1_Click(object sender, EventArgs e)         {             for (int i = 0; i < 10000; i++)            

  • IIS应用程序池自动停止 关闭 假死 处理集锦

    1:没有打SP1补丁的时候会出现这个IIS6.0假死问题,但现在微软都在自动更新里面出补丁了,一般你打好最新补丁后是不会出现此问题了 2:你限制了应用池 的资源过小 3:你限制了内存使用 4:就是服务器自身内存太小 5:就是ACCESS数据库太大或查询太多 6:不同网站用不同应用池 7:设置回收时间,很多人以为设置回收池越短越好,其实是错误的 8:windows 2003系统iis6访问本机的站点时提示"Service Unavailable": 查看iis的应用程序池,状况提示为:未

  • IIS假死的解决方法 缩短IIS应用池回收时间来实现减少IIS假死

    IIS日志: 应用程序:ISAPI 'C:\WINDOWS\system32\inetsrv\asp.dll' 报告它自身有问题,原因如下: 'ASP 不正常,因为执行请求的 100% 被挂起,而且请求队列已经使用了 0%.'. 关于 server 2003+IIS6 出现 'ASP 不正常,因为执行请求的 100% 被挂起 现像如下: 站点无法打开,或者打开很慢.HTML可以打开.重新启动或者回收应用程序池可恢复.但过一段时间又会出现 日志里会有: ISAPI 'C:\WINDOWS\syst

随机推荐