排查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优化服务之网页压缩的实现方法
Mar 31 Servers
Linux安装Nginx步骤详解
Mar 31 Servers
Nginx搭建rtmp直播服务器实现代码
Mar 31 Servers
win10安装配置nginx的过程
Mar 31 Servers
iSCSI服务器CHAP双向认证配置
Apr 01 Servers
CentOS7和8下安装Maven3.8.4
Apr 07 Servers
Nginx+Tomcat负载均衡多实例详解
Apr 11 Servers
tomcat正常启动但网页却无法访问的几种解决方法
May 06 Servers
阿里云国际版 使用Nginx作为HTTPS转发代理服务器
May 11 Servers
使用Nginx+Tomcat实现负载均衡的全过程
May 30 Servers
Win Server2016远程桌面如何允许多用户同时登录
Jun 10 Servers
git stash(储藏)的用法总结
Jun 25 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
PHP循环结构实例讲解
2014/02/10 PHP
浅谈ThinkPHP的URL重写
2014/11/25 PHP
php中的常用魔术方法汇总
2016/02/14 PHP
Yii框架参数配置文件params用法实例分析
2019/09/11 PHP
最近项目写了一些js,水平有待提高
2009/01/31 Javascript
Jquery UI震动效果实现原理及步骤
2013/02/04 Javascript
QQ空间顶部折页撕开效果示例代码
2014/06/15 Javascript
Javascript中的默认参数详解
2014/10/22 Javascript
jQuery中常用的遍历函数用法实例总结
2015/09/01 Javascript
学习JavaScript设计模式(策略模式)
2015/11/26 Javascript
Bootstrap 最常用的JS插件系列总结(图片轮播、标签切换等)
2016/07/14 Javascript
javascript基于原型链的继承及call和apply函数用法分析
2016/12/15 Javascript
Bootstrap媒体对象学习使用
2017/03/07 Javascript
React.js中常用的ES6写法总结(推荐)
2017/05/09 Javascript
vue2.x+webpack快速搭建前端项目框架详解
2017/11/30 Javascript
js中int和string数据类型互相转化实例
2019/01/16 Javascript
Vue过滤器,生命周期函数和vue-resource简单介绍
2021/01/12 Vue.js
python并发编程之多进程、多线程、异步和协程详解
2016/10/28 Python
Python实现的科学计算器功能示例
2017/08/04 Python
解决DataFrame排序sort的问题
2018/06/07 Python
python 根据时间来生成唯一的字符串方法
2019/01/14 Python
python dlib人脸识别代码实例
2019/04/04 Python
python绘制双Y轴折线图以及单Y轴双变量柱状图的实例
2019/07/08 Python
Python解析多帧dicom数据详解
2020/01/13 Python
pycharm运行程序时看不到任何结果显示的解决
2020/02/21 Python
python使用turtle库绘制奥运五环
2020/02/24 Python
HTML5实现预览本地图片
2016/02/17 HTML / CSS
Hotels.com拉丁美洲:从豪华酒店到经济型酒店的预定优惠和折扣
2019/12/09 全球购物
2019年Java 最常见的 面试题
2016/10/19 面试题
后勤岗位职责
2013/11/26 职场文书
全国税务系统先进集体事迹材料
2014/05/19 职场文书
股东出资证明书范例
2014/10/04 职场文书
股份转让协议书范本
2015/01/27 职场文书
办公室管理规章制度
2015/08/04 职场文书
导游词之镇江-金山寺
2019/10/14 职场文书
正则表达式拆分url实例代码
2022/02/24 Java/Android