排查Tomcat进程假死的问题


Posted in Servers onMay 06, 2022

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运行情况

排查Tomcat进程假死的问题

 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配置文件,修改最大连接数(增大)

排查Tomcat进程假死的问题

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

排查Tomcat进程假死的问题

 到此这篇关于Tomcat进程假死问题排查的文章就介绍到这了!


Tags in this post...

Servers 相关文章推荐
Nginx 根据URL带的参数转发的实现
Apr 01 Servers
关于nginx 实现jira反向代理的问题
Sep 25 Servers
详解nginx安装过程并代理下载服务器文件
Feb 12 Servers
HDFS免重启挂载新磁盘
Apr 06 Servers
Nginx配置根据url参数重定向
Apr 11 Servers
nginx location 带斜杠【 / 】与不带的区别
Apr 13 Servers
nginx lua 操作 mysql
May 15 Servers
Nginx限流和黑名单配置
May 20 Servers
nginx rewrite功能使用场景分析
May 30 Servers
在虚拟机中安装windows server 2008的图文教程
Jun 28 Servers
Docker部署Mysql8的实现步骤
Jul 07 Servers
centos环境下nginx高可用集群的搭建指南
Jul 23 Servers
使用Nginx的访问日志统计PV与UV
Tomcat配置访问日志和线程数
May 06 #Servers
tomcat正常启动但网页却无法访问的几种解决方法
May 06 #Servers
tomcat默认最大连接数及相关调整方法
May 06 #Servers
如何Tomcat中使用ipv6地址
May 06 #Servers
Tomcat弱口令复现及利用
Vscode中SSH插件如何远程连接Linux
You might like
mac下Apache + MySql + PHP搭建网站开发环境
2014/06/02 PHP
PHP中的Session对象如何使用
2015/09/25 PHP
学习php设计模式 php实现原型模式(prototype)
2015/12/07 PHP
php实现微信模板消息推送
2018/03/30 PHP
根据分辨率不同,调用不同的css文件
2006/08/25 Javascript
关于js中window.location.href,location.href,parent.location.href,top.location.href的用法与区别
2010/10/18 Javascript
web的各种前端打印方法之jquery打印插件PrintArea实现网页打印
2013/01/09 Javascript
jquery实现select选中行、列合计示例
2014/04/25 Javascript
教你如何使用PHP输出中文JSON字符串
2014/05/22 Javascript
深入分析JSONP跨域的原理
2014/12/10 Javascript
解决Jquery向页面append新元素之后事件的绑定问题
2015/03/16 Javascript
详解JavaScript的策略模式编程
2015/06/24 Javascript
JS插件overlib用法实例详解
2015/12/26 Javascript
JS瀑布流实现方法实例分析
2016/12/19 Javascript
vue实现新闻展示页的步骤详解
2019/04/11 Javascript
微信小程序实现收货地址左滑删除
2020/11/18 Javascript
[56:21]LGD vs IG 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
[03:13]DOTA2-DPC中国联赛1月25日Recap集锦
2021/03/11 DOTA
python 随机数生成的代码的详细分析
2011/05/15 Python
python实现爬虫统计学校BBS男女比例(一)
2015/12/31 Python
常见的python正则用法实例讲解
2016/06/21 Python
Python更新数据库脚本两种方法及对比介绍
2017/07/27 Python
Python Sympy计算梯度、散度和旋度的实例
2019/12/06 Python
在Django中预防CSRF攻击的操作
2020/03/13 Python
Keras 实现加载预训练模型并冻结网络的层
2020/06/15 Python
为什么是 Python -m
2020/06/19 Python
Python之多进程与多线程的使用
2021/02/23 Python
详解CSS3的box-shadow属性制作边框阴影效果的方法
2016/05/10 HTML / CSS
CSS3实现各种图形的示例代码
2016/10/19 HTML / CSS
美国在线购物频道:Shop LC
2019/04/21 全球购物
初一学生评语大全
2014/04/24 职场文书
房产公证委托书范本
2014/09/20 职场文书
中学后勤工作总结2015
2015/07/22 职场文书
高中班长竞选稿
2015/11/20 职场文书
MySQL基于索引的压力测试的实现
2021/11/07 MySQL
Python制作表白爱心合集
2022/01/22 Python