JVM对于signal的处理及案例分析

如题所述

第1个回答  2022-07-04

Windows的Signal相对少一些, 如下:

Linux的Signal比较多, 如下:

Linux中的Signal可以由 kill 命令发起, 比如 kill -1 [pid] 是对某一个进程发出SIGHUP信息.

JVM 所使用的信号:

信号的类型为 异常、错误、中断和控制

表 1

注:

信号名称后提供的数字是该信号的标准数值。

使用 -Xrs(减少信号使用)选项来防止 JVM 处理大多数的信号。有关更多信息,请参阅 Oracle 的 Java™ 应用程序启动程序页面 。

JVM 线程上的信号 1(SIGHUP)、2(SIGINT)、4(SIGILL)、7(SIGBUS)、8(SIGFPE)、11(SIGSEGV)和 15(SIGTERM)导致 JVM 关闭;因此,应用程序信号处理程序不应该尝试从这些信号恢复,除非它不再需要 JVM。

以上表格引用原文链接:

https://www.ibm.com/support/knowledgecenter/zh/SSYKE2_7.0.0/com.ibm.java.lnx.70.doc/user/sighand.html

至于JVM是如何处理这些Signal的, 请参考以下链接:

https://www.ibm.com/support/knowledgecenter/zh/SSYKE2_7.0.0/com.ibm.java.lnx.70.doc/user/signals.html

除了JVM默认处理Signal的行为, 我们还可以自定义 SignalHandler 来做一些额外的工作, 比如在关闭JVM之前做一些回收或记录的事情.

例子:

关闭钩子使用的方法也很简单, Runtime.getRuntime().addShutdownHook(Thread hook) 即可。关闭钩子其实可以看成是一个已经初始化了的但还没启动的线程,当 JVM关闭时会并发地执行注册的所有关闭钩子

JVM的关闭方式可以分为三种:

注意: Hook线程在JVM 正常关闭 才会执行,在强制关闭时不会执行。(异常关闭没试过, 有空试一下..)

另外在使用关闭钩子还要注意以下几点:

Spring 在初始化容器的时候就会注册一个hook线程用于清理容器.

[图片上传失败...(image-3b9611-1513089974690)]

JVM进程已经不在了, 重启后, 几分钟到半小时之间, 会看到获取不到spring bean的错误日志, 同时系统服务异常.

[图片上传失败...(image-cfc2ef-1513089974690)]

奇怪的是, 2台集群中的其他一台一直都是稳定运行, 只有这台是一直异常状态.

从以上的日志, 可以看出spring容器已经在销毁中了, 感觉是一个正常的关闭系统的流程.

在监控系统(Marvin)中观察了内存的情况, 没有什么波动, 基本排除了oom的情况.

接下来, 我使用jstack输出了当时的线程栈信息, 保留现场痕迹.

[图片上传失败...(image-508b17-1513089974690)]

由上图所示, 从jstack日志中发现了2个关键的点:

自此, 大家可能已经看出来, SIGHUP 正是JVM会处理的Signal之一, 并且在上面的表格中已经清楚的写着 SIGHUP 的操作是 挂起, 让JVM正常退出 , SIGHUP 中断 类型的信号, 上面对于 中断 类型的信号是这样描述的: 将从 JVM 进程外部异步发出中断信号以请求关闭。

结论:

可惜的是, 找了很多资料, 始终没有找到确定信号来源的方案. Linux本身也没有相关的日志, JVM也只能获取信号的名称, 对于信号源也是无法确定.(如果有这方面研究的同学望告知..)

找不到根本原因, 那么只能是想办法绕过这个问题.

所幸的是, 在搜索问题的时候, 让我知道了Linux还有一个 nohup 的命令.

nohup命令可以将 程序以忽略挂起信号( SIGHUP)的方式运行起来,被运行的程序的输出信息将不会显示到终端。

于是把JVM的启动脚本改动了一下:

[图片上传失败...(image-7897ca-1513089974690)]

再次启动后, 稳定运行, 问题解决.

实际上通过JVM本身 -Xrs 的参数应该也能控制忽略SIGHUP信号的, 但是时间关系, 我没去实验..

这里案例也让我学到了很多JVM的处理细节.

同时也有了一些思考:

排查线上故障的基本步骤无非就是

实际上, 前面3步基本上已经能解决大部分的问题了, 剩下的一些疑难问题才会用到第4步. 但是第4步的操作对于实时性的要求是最高的, 必须第一时间搞定, 晚一点可能你就捕捉不到有效的证据了.

在出现故障的情况下, 有时候难免手忙脚乱, 如果有一个可以自动化收集现场证据的脚本, 在出现这种疑难问题的时候将会是一个极大的助力.