排查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 相关文章推荐
Centos7.7 64位利用本地完整安装包安装lnmp/lamp套件教程
Mar 09 Servers
Nginx已编译的nginx-添加新模块
Apr 01 Servers
教你快速开启Apache SkyWalking的自监控
Apr 25 Servers
使用 Apache Superset 可视化 ClickHouse 数据的两种方法
Jul 07 Servers
Nginx内网单机反向代理的实现
Nov 07 Servers
Apache POI的基本使用详解
Nov 07 Servers
基于docker安装zabbix的详细教程
Jun 05 Servers
阿里云服务器(windows)手动部署FTP站点详细教程
Aug 05 Servers
Linux在两个服务器直接传文件的操作方法
Aug 05 Servers
SpringBoot前端后端分离之Nginx服务器下载安装过程
Aug 14 Servers
源码安装apache脚本部署过程详解
Sep 23 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
PHP中一个控制字符串输出的函数
2006/10/09 PHP
一个简单的网页密码登陆php代码
2012/07/17 PHP
php  PATH_SEPARATOR判断当前服务器系统类型实例
2016/10/28 PHP
微信公众号OAuth2.0网页授权问题浅析
2017/01/21 PHP
jquery 输入框数字限制插件
2009/11/10 Javascript
javascript中的new使用
2010/03/20 Javascript
jQuery实现表格颜色交替显示的方法
2015/03/09 Javascript
JavaScript对Json的增删改属性详解
2016/06/02 Javascript
浅谈在js传递参数中含加号(+)的处理方式
2016/10/11 Javascript
微信小程序 解决swiper不显示图片的方法
2017/01/04 Javascript
angular实现IM聊天图片发送实例
2017/05/08 Javascript
深入理解ES6学习笔记之块级作用域绑定
2017/08/19 Javascript
mui back 返回刷新页面的实例
2017/12/06 Javascript
详解webpack babel的配置
2018/01/09 Javascript
写一个移动端惯性滑动&回弹Vue导航栏组件 ly-tab
2018/03/06 Javascript
JS秒杀倒计时功能完整实例【使用jQuery3.1.1】
2019/09/03 jQuery
使用layer.msg 时间设置不起作用的解决方法
2019/09/12 Javascript
vue中英文切换实例代码
2020/01/21 Javascript
JavaScript设计模式---单例模式详解【四种基本形式】
2020/05/16 Javascript
python查询sqlite数据表的方法
2015/05/08 Python
简单解决Python文件中文编码问题
2015/11/22 Python
详解Python nose单元测试框架的安装与使用
2017/12/20 Python
python并发编程多进程 模拟抢票实现过程
2019/08/20 Python
python 两个数据库postgresql对比
2019/10/21 Python
django数据模型(Model)的字段类型解析
2019/12/25 Python
Python callable内置函数原理解析
2020/03/05 Python
python制作一个简单的gui 数据库查询界面
2020/11/19 Python
HTML5实现预览本地图片
2016/02/17 HTML / CSS
西班牙宠物用品和食品网上商店:Tiendanimal
2019/06/06 全球购物
个人简历的自荐信
2013/10/23 职场文书
大龄毕业生求职别忘职业规划
2014/03/11 职场文书
《鸟岛》教学反思
2014/04/26 职场文书
火灾现场处置方案
2014/05/28 职场文书
教育实践活动对照检查材料
2014/09/23 职场文书
普通党员四风问题对照检查材料
2014/09/27 职场文书
小学语文继续教育研修日志
2015/11/13 职场文书