排查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 + consul + upsync 完成动态负载均衡的方法详解
Mar 31 Servers
Nginx服务器如何设置url链接
Mar 31 Servers
Nginx反向代理及负载均衡如何实现(基于linux)
Mar 31 Servers
Mac环境Nginx配置和访问本地静态资源的实现
Mar 31 Servers
Nginx反爬虫策略,防止UA抓取网站
Mar 31 Servers
利用Nginx代理如何解决前端跨域问题详析
Apr 02 Servers
使用goaccess分析nginx日志的详细方法
Jul 09 Servers
深入解析Apache Hudi内核文件标记机制
Mar 31 Servers
Consul在linux环境的集群部署
Apr 08 Servers
使用Nginx+Tomcat实现负载均衡的全过程
May 30 Servers
Windows Server 2012 R2服务器安装与配置的完整步骤
Jul 15 Servers
服务器nginx权限被拒绝解决案例
Sep 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
递归列出所有文件和目录
2006/10/09 PHP
浅析php中常量,变量的作用域和生存周期
2013/08/10 PHP
PHP封装的XML简单操作类完整实例
2017/11/13 PHP
tp5实现微信小程序多图片上传到服务器功能
2018/07/16 PHP
如何将一个String和多个String值进行比较思路分析
2013/04/22 Javascript
jquery实现带单选按钮的表格行选中时高亮显示
2013/08/01 Javascript
JS JSON对象转为字符串的简单实现方法
2013/11/18 Javascript
JQuery中ajax方法访问web服务实例
2015/07/18 Javascript
详解微信小程序入门五: wxml文件引用、模版、生命周期
2017/01/20 Javascript
微信小程序 九宫格实例代码
2017/01/21 Javascript
Node.js 使用命令行工具检查更新
2017/06/08 Javascript
在vue-cli脚手架中配置一个vue-router前端路由
2017/07/03 Javascript
关于Promise 异步编程的实例讲解
2017/09/01 Javascript
JS笛卡尔积算法与多重数组笛卡尔积实现方法示例
2017/12/01 Javascript
js实现购物车功能
2018/06/12 Javascript
vue首次赋值不触发watch的解决方法
2018/09/11 Javascript
微信小程序可滑动周日历组件使用详解
2019/10/21 Javascript
JS 设计模式之:工厂模式定义与实现方法浅析
2020/05/06 Javascript
js瀑布流布局的实现
2020/06/28 Javascript
Python导出数据到Excel可读取的CSV文件的方法
2015/05/12 Python
Python中使用urllib2模块编写爬虫的简单上手示例
2016/01/20 Python
Python之ReportLab绘制条形码和二维码的实例
2018/01/15 Python
浅谈django orm 优化
2018/08/18 Python
Python线程同步的实现代码
2018/10/03 Python
django用户登录验证的完整示例代码
2019/07/21 Python
Python使用Opencv实现图像特征检测与匹配的方法
2019/10/30 Python
Pytorch 实现冻结指定卷积层的参数
2020/01/06 Python
SQL面试题
2013/12/09 面试题
单位提档介绍信
2014/01/17 职场文书
建筑个人求职信范文
2014/01/25 职场文书
餐饮采购员岗位职责
2014/03/15 职场文书
阳光体育活动实施方案
2014/05/25 职场文书
开票证明
2015/06/23 职场文书
统招统分证明
2015/06/23 职场文书
nginx共享内存的机制详解
2022/03/21 Servers
JS实现九宫格拼图游戏
2022/06/28 Javascript