CLOSE_WAIT lead to a production environment, a large number of services can not access the positioning process

1. Symptoms

A service of the production environment suddenly inaccessible, as shown in the interactive service process is as follows:
Here Insert Picture Description
all requests are at the gateway, and then distributed to the back-end service.

The current situation is a user service can not access Business services, Gateway has a large number of java.net.SocketTimeoutException: Read timed outerror logs, Business Services also continue to have log printing, most of the callback and timing task log, so the point of failure in the gateway and Business Services, the high probability is business travel services inaccessible lead gateway timeout.

Subsequent operations executed as follows:

  • Restart Business services, access to normal after a few hours and can not access the service
  • Restart Gateway, still can not access the service, and then restart Business Services, a normal visit, after a few hours and can not access the service
  • Business users call path test interface can not be accessed; access to business travel path test interface on the gateway machine, still can not access;
  • Business after the restart, the test interface can be accessed via the gateway Business machine

Through the above operations it can be concluded that the gateway is OK, the point of failure in the Business Services.

2. The first positioning

Operation and maintenance using the Top command (similar to Windows Task Manager) to see what happens in the machine, as shown below (for reference only):
Here Insert Picture Description

Parameters are explained as follows:
 VIRT: virtual memory occupied by the process
 RES: process takes physical memory
 SHR: shared memory used by the process
 state of the process: S. S indicates sleep, R represents a running, Z represents a dead state, N is negative indicates that the process priority
 % CPU: process CPU utilization
 % MEM: percentage of physical memory and total memory used by the process

Execution netstat -nat | grep "CLOSE_WAIT"found a large number of CLOSE_WAITconnections. Refer to the following:
Here Insert Picture Description
Business JVM heap memory limit to 512M, but shown above using the 988M (much larger), then combined experience in operation and maintenance JDK7 升级到JDK8后一些JVM参数实效, now looked JVM parameters used to -ms512m -mx512m, this is considered to be an old JVM parameters. So we conclude that the JVM parameters lead to failure of memory is not locked, multiple JVM memory contention lead service is unavailable. Then made the following solution:
the JVM startup parameters from the -ms512m -mx512mchange –Xms256m –Xmx512m, restart service, normal access.

3. The second positioning

After about less than a day, they can not access the service, top command and the first results are consistent positioning, it is still considered to be at this time JVM parameter is not in effect, compete with each other resulting in memory. Because there are people waiting for tickets online services, so the first implementation of jmap -dump:format=b,file=文件名 [pid]the export dump file for subsequent positioning, and then restart the service back to normal.

Analysis Dump file that you can use jhat、MAT、jvisualvmto analyze, view the JVM heap memory usage, memory overflow in order to find the reason.
As Thread Dump files record the circumstances of the JVM thread running the same, Heap Dump documented the JVM heap memory to run.

jhatIt is JDK comes with tools for analyzing JVM Heap Dump file, use the jhat <heap-dump-file>command stack of file analysis results can be displayed in a form of an HTML page, showing the following results after successful execution: Snapshot resolved.Started HTTP server on port 7000Server is ready.this time to visit http: // localhost: 7000 / We can see the results. But the reality is generally used MAT、jvisualvmto analyze.

建议在JVM启动时增加-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=c:/heap.bin参数,所代表的含义就是当程序出现OutofMemory时,将会在相应的目录下生成一份dump文件,而如果不指定选项“XX:HeapDumpPath”则在当前目录下生成dump文件。尽管不借助jmap工具,MAT工具也能够直接生成dump文件,但是考虑到生产环境中几乎不可能在线对其进行分析,大都是采用离线分析,因此使用jmap+MAT工具是最常见的组合。

3.1使用jvisualvm

jvisualvm是JDK自带的Java性能分析工具,在JDK的bin目录下,文件名就叫jvisualvm.exe
jvisualvm可以监控本地、远程的java进程,实时查看进程的cpu、堆、线程等参数,对java进程生成dump文件,并对dump文件进行分析。
本次是从服务器上dump下来文件,扔给jvisualvm来分析。
使用方式:直接双击打开jvisualvm.exe,点击文件->装入,在文件类型那一栏选择堆,选择要分析的dump文件,打开。
Here Insert Picture Description
通过分析,并未发现异常,没有内存泄露的痕迹,也没有异常的大的对象。

3.2 Eclipse Memory Analyzer(MAT)

Eclipse Memory Analyzer(简称MAT)是一个功能丰富且操作简单的JVM Heap Dump分析工具,可以用来辅助发现内存泄漏减少内存占用。
MAT支持两种安装方式,一是Eclipse插件的方式,另外一个就是独立运行的方式,建议使用独立运行的方式。
分析结果如下:
Overview:概要界面,显示了概要的信息
Here Insert Picture Description
Histogram: 直方图,可以查看每个类的实例(即对象)的数量和大小。
Here Insert Picture Description
Dominator Tree:支配树,列出Heap Dump中处于活跃状态中的最大的几个对象,默认按 retained size进行排序,因此很容易找到占用内存最多的对象。
Here Insert Picture Description
通过分析,均无内存溢出的痕迹,也无大对象等。MAT用法详见:
Java内存泄漏分析系列之六:JVM Heap Dump(堆转储文件)的生成和MAT的使用
Java内存分析工具MAT(Memory Analyzer Tool)安装使用实例

3.3结论

商旅服务无内存泄露的问题,也不存在内存争用的问题(下面会讲),定位的方向最初就是错误的,于是换思路重新定位问题。

4.第三次定位

很快,服务有发生了不可访问,不过这次的重点放在了已近有一些征兆的CLOSE_WAIT上。

4.1 文确认件描述符超出限制导致

执行ulimit -a, 发现open files是65535,已经做过了优化,不是fd的问题。
查看商旅进程使用的Fd数量(统计进程打开的句柄数)。ls -l /proc/pid/fd | wc -l结果如下,打开的确实很多,但是距离65535相差甚远。
Here Insert Picture Description

4.2 查看堆的情况

执行jmap -heap pid查看堆信息,一切正常,最大堆设置已经生效。
Here Insert Picture Description
对应关系,给张图自己体会:
Here Insert Picture Description
最大堆为512M,但是top命令看到实际使用了988M,什么原因?
Here Insert Picture Description
什么是RES和VIRT?

  • RES:resident memory usage 常驻内存
    (1)进程当前使用的内存大小,但不包括swap out
    (2)包含其他进程的共享
    (3)如果申请100m的内存,实际使用10m,它只增长10m,与VIRT相反
    (4)关于库占用内存的情况,它只统计加载的库文件所占内存大小
    RES = CODE + DATA

  • VIRT:virtual memory usage
    (1)进程“需要的”虚拟内存大小,包括进程使用的库、代码、数据等
    (2)假如进程申请100m的内存,但实际只使用了10m,那么它会增长100m,而不是实际的使用量
    VIRT = SWAP + RES

Linux与进程内存模型
Here Insert Picture Description
JVM内存模型(1.7与1.8之间的区别)
Here Insert Picture Description

所以JVM进程内存大小大致为:
非heap(非heap=元空间+栈内存+…)+heap+JVM进程运行所需内存+其他数据等。

所以对应到商旅988M= 512M(堆) + 283 *1M(283个线程,每个线程占用1M)+JVM进程本身运行内存+ NIO的DirectBuffer +JIT+JNI+…,所以top命令显示出的实际内存大于512是合理的。

使用系统命令pmap -x pid查看进程的内存映射情况,会发现大量的六十多MB内存块存在,这个就表示申请了这么大的内存(影响VIRT),但是实际使用的肯定小于这个值(影响RES),这也解释了为什么VIRT很大,几个G。
Here Insert Picture Description

4.3 查看商旅进程中的线程数

执行ls /proc/17493/task |wc -l(统计进程打开的线程数),结果如下:
Here Insert Picture Description
总计283个线程。也不是很多。

4.4查看GC情况

执行jstat -gc pid或者stat -gc pid 5000 2000
Here Insert Picture Description
gc的次数也不是很多,时间也不长。

4.5TCP连接状态统计

执行netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'统计TCP状态情况,
Here Insert Picture Description
常用的三个状态是:ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭 因为linux分配给一个用户的文件句柄是有限的,而TIME_WAIT和CLOSE_WAIT两种状态如果一直被保持,那么意味着对应数目的通道就一直被占着,而且是“占着茅坑不使劲”,一旦达到句柄数上限,新的请求就无法被处理了,接着就是大量Too Many Open Files异常;如果未达到句柄数上限,也可能会出现无连接可用的情况。
上面发现大量的连接处于CLOSE_WAIT,这可能就是服务不可访问的原因。
这说明是客户端先关闭了连接,服务器端没有执行关闭连接的操作,导致服务器端一直维持在CLOSE_WAIT的状态。详见下图:
Here Insert Picture Description

查看TCP的keep_alive参数sysctl -a |grep keepalive ,结果如下:
Here Insert Picture Description
TCP默认的保活时间为2个小时,也就是说两个小时TCP才会主动帮我们会清理一次无用的连接。所以现在的问题是什么原因造成了大量CLOSE_WAIT的产生。

TIME_WAIT状态可以通过优化服务器参数得到解决,因为发生TIME_WAIT的情况一般是就是对方连接的异常,总之不是由于自己程序错误导致的。

但是CLOSE_WAIT就不一样了,如果一直保持在CLOSE_WAIT状态,那么只有一种情况,就是在对方连接关闭之后,程序里没有检测到,或者程序压根就忘记了这个时候需要关闭连接,于是这个资源就一直被程序占着。个人觉得这种情况,通过服务器内核参数也没办法解决,服务器对于程序抢占的资源没有主动回收的权利,除非终止程序运行。
所以如果将大量CLOSE_WAIT的解决办法总结为一句话那就是:查代码。因为问题出在服务器程序里头啊。

5.找到问题并复现

大量CLOSE_WAIT是则么出现的呢?一下两个线索为我们提供了思路:

  • 生产的日志大多是同城火车票回调
  • 同城火车票目前只有测试环境,回调地址配置到了生产环境,而开发、黑盒、沙河无回调,使用主动查询逻辑。
  • 同城火车票上线之前服务正常

一个定位的方向就是:同城的回调导致大量CLOSE_WAIT,于是走读代码,果然有端倪.
Here Insert Picture Description
这段代码的大致意思是: 收到回调,查询订单是否存在,存在则处理,不存在则执行30的睡眠,之后返回。(不要问为什么有这样的逻辑)。

同程回调接口是这样说明的:
Here Insert Picture Description
所以原因是:开发、黑盒、沙河、生产为了发版本产生了大量的订单、但是只有生产配置了回调地址,所以有大量的回调到生产环境,但是很多单子不是生产环境的,所以导致Sleep了30S,于是在回调返回之前,同城已经超时,程服务端直接关闭连接,同时会再次发送新的回调。一直不停的这样,这样商旅通服务端会造成大量CLOSE_WAIT堆积,一个CLOSE_WAIT会维持至少2个小时的时间(系统默认超时时间的是7200秒,也就是2小时)。

造成CLOSE_WAIT占用过多的资源,等不到释放那一刻,系统就已崩溃。
Here Insert Picture Description

6.解决

Production environment finding out orders to return immediately, without SLEEP.
After the upgrade the production environment, within a few days, the problem is solved.

7. References

Published 418 original articles · won praise 745 · Views 1.26 million +

Guess you like

Origin blog.csdn.net/u013467442/article/details/90375361