排查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 相关文章推荐
Apache站点配置SSL强制跳转443
Mar 09 Servers
Nginx优化服务之网页压缩的实现方法
Mar 31 Servers
apache基于端口创建虚拟主机的示例
Apr 24 Servers
nginx请求限制配置方法
Jul 09 Servers
Nginx动静分离配置实现与说明
Apr 07 Servers
Docker官方工具docker-registry案例演示
Apr 13 Servers
解决Windows Server2012 R2 无法安装 .NET Framework 3.5
Apr 29 Servers
ubuntu下常用apt命令介绍
Jun 05 Servers
windows server 2016 域环境搭建的方法步骤(图文)
Jun 25 Servers
教你nginx跳转配置的四种方式
Jul 07 Servers
windows10 家庭版下FTP服务器搭建教程
Aug 05 Servers
ubuntu20.04虚拟机无法上网的问题及解决
Dec 24 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
牡丹941资料
2021/03/01 无线电
如何在PHP中使用Oracle数据库(2)
2006/10/09 PHP
用PHP将数据导入到Foxmail的实现代码
2010/09/05 PHP
PHP根据两点间的经纬度计算距离
2014/10/31 PHP
php实现网页缓存的工具类分享
2015/07/14 PHP
Laravel使用支付宝进行支付的示例代码
2017/08/16 PHP
PHP实现一个多功能购物网站的案例
2017/09/13 PHP
js事件监听机制(事件捕获)总结
2014/08/08 Javascript
JavaScript 学习笔记之操作符
2015/01/14 Javascript
自己动手手写jQuery插件总结
2015/01/20 Javascript
深入理解JQuery循环绑定事件
2016/06/02 Javascript
js拼接html字符串的注意事项
2016/10/13 Javascript
C#微信小程序服务端获取用户解密信息实例代码
2017/03/10 Javascript
学习使用Bootstrap栅格系统
2017/05/11 Javascript
javascript基于定时器实现进度条功能实例
2017/10/13 Javascript
D3.js(v3)+react 实现带坐标与比例尺的柱形图 (V3版本)
2019/05/09 Javascript
[16:04]DOTA2海涛带你玩炸弹 9月5日更新内容详解
2014/09/05 DOTA
python用ConfigObj读写配置文件的实现代码
2013/03/04 Python
tensorflow 1.0用CNN进行图像分类
2018/04/15 Python
Python3爬虫爬取英雄联盟高清桌面壁纸功能示例【基于Scrapy框架】
2018/12/05 Python
jupyter notebook参数化运行python方式
2020/04/10 Python
Python求凸包及多边形面积教程
2020/04/12 Python
python中requests模拟登录的三种方式(携带cookie/session进行请求网站)
2020/11/17 Python
详解Python中的Lock和Rlock
2021/01/26 Python
美国大城市最热门旅游景点门票:CityPASS
2016/12/16 全球购物
英国大码女性时装零售商:Evans
2018/08/29 全球购物
Strawberrynet草莓网新加坡站:护肤、彩妆、香水及美发产品
2018/08/31 全球购物
Perfume’s Club德国官网:在线购买香水
2019/04/08 全球购物
党的群众路线教育实践活动批评与自我批评
2014/02/16 职场文书
《童趣》教学反思
2014/02/19 职场文书
广告语设计及教案
2014/03/21 职场文书
一年级小学生评语
2014/04/22 职场文书
会议室标语
2014/06/21 职场文书
英语复习计划
2015/01/19 职场文书
欠款起诉书范文
2015/05/19 职场文书
教研活动主持词
2015/07/03 职场文书