老板:kill -9 的原理都不知道就敢去线上执行?明天不用来了!

GitHub 14.5k Star 的Java工程师成神之路,开放阅读了!

信赖许多程序员对于Linux系统都不生疏,纵然自己的一样平常开发机械不是Linux,那么线上服务器也大部门都是的,以是,掌握常用的Linux下令也是程序员必备的技术。

然则,怕就怕许多人对于部门下令只是一知半解,使用不当就能导致线上故障。

前段时间,我们的线上应用报警,频仍FGC,需要紧要处置问题,于是有同事去线上重启机械(正常程序应该是先采集堆dump,然后再重启,利便排查是否存在内存泄露等问题)。

然则在重启过程中,同事发现正常的重启下令应用无反映,然后实验使用kill下令”杀”掉Java历程,然则仍然无效。于是他私自决议使用 “kill -9″竣事了历程的生命。

虽然应用历程被干掉了,然则随之而来带来了许多问题,首先是上游系统突然发生大量报警,对应开发找过来说挪用我们的RPC服务无响应,频仍超时。

厥后,我们又发现系统中存在部门脏数据,有些在同一个事务中需要完整更新的数据,只跟新了一半…

为什么正常的kill无法”杀掉”历程,而kill -9就可以?为什么kill -9会引发这一连串连锁反映?正常的kill执行时,JVM会若何处置的呢?

要搞清楚这些问题,我们要先从kill下令提及。

kill 下令

我们都知道,想要在Linux中终止一个历程有两种方式,若是是前台历程可以使用Ctrl+C键举行终止;若是是后台历程,那么需要使用kill下令来终止。(实在Ctrl+C也是kill下令)

kill下令的花样是:

kill[参数][历程号]

如:
kill 21121
kill -9 21121

其中[参数]是可选的,历程号可以通过jps/ps/pidof/pstree/top等工具获取。

kill的下令参数有以下几种:

-l 信号,若果不加信号的编号参数,则使用“-l”参数会列出所有的信号名称

-a 当处置当前历程时,不限制下令名和历程号的对应关系

-p 指定kill 下令只打印相关历程的历程号,而不发送任何信号

-s 指定发送信号

-u 指定用户

通常情况下,我们使用的-l(信号)的时刻对照多,如我们前文提到的kill -9中的9就是信号。

信号若是没有指定的话,默认会发出终止信号(15)。常用的信号如下:

HUP 1 终端断线

INT 2 中止(同 Ctrl + C)

QUIT 3 退出(同 Ctrl + \)

TERM 15 终止

KILL 9 强制终止

CONT 18 继续(与STOP相反, fg/bg下令)

STOP 19 暂停(同 Ctrl + Z)

对照常用的就是强制终止信号:9终止信号:15,另外,中止信号:2实在就是我们前文提到的Ctrl + C竣事前台历程。

那么,kill -9kill -15到底有什么区别呢?该若何选择呢?

kill -9 和 kill -15的区别

kill下令默认的信号就是15,首先来说一下这个默认的kill -15信号。

当使用kill -15时,系统会发送一个SIGTERM的信号给对应的程序。当程序接收到该信号后,具体要若何处置是自己可以决议的。

「从零单排HBase 10」HBase集群多租户实践

这时刻,应用程序可以选择:

  • 1、立刻住手程序

  • 2、释放响应资源后住手程序

  • 3、忽略该信号,继续执行程序

由于kill -15信号只是通知对应的历程要举行”平安、清洁的退出”,程序接到信号之后,退出前一样平常会举行一些”准备工作”,如资源释放、临时文件清算等等,若是准备工作做完了,再举行程序的终止。

然则,若是在”准备工作”举行过程中,遇到壅闭或者其他问题导致无法乐成,那么应用程序可以选择忽略该终止信号。

这也就是为什么我们有的时刻使用kill下令是没办法”杀死”应用的缘故原由,由于默认的kill信号是SIGTERM(15),而SIGTERM(15)的信号是可以被壅闭和忽略的。

kill -15相比,kill -9就相对强硬一点,系统会发出SIGKILL信号,他要求接收到该信号的程序应该立刻竣事运行,不能被壅闭或者忽略。

以是,相比于kill -15下令,kill -9在执行时,应用程序是没有时间举行”准备工作”的,以是这通常会带来一些副作用,数据丢失或者终端无法恢复到正常状态等。

Java是若何处置SIGTERM(15)的

我们都知道,在Linux中,Java应用是作为一个自力历程运行的,Java程序的终止运行是基于JVM的关闭实现的,JVM关闭方式分为3种:

正常关闭:当最后一个非守护线程竣事或者挪用了System.exit或者通过其他特定平台的方式关闭(接收到SIGINT(2)、SIGTERM(15)信号等)

强制关闭:通过挪用Runtime.halt方式或者是在操作系统中强制kill(接收到SIGKILL(9)信号)

异常关闭:运行中遇到RuntimeException异常等。

JVM历程在接收到kill -15信号通知的时刻,是可以做一些清算动作的,好比删除临时文件等。

固然,开发者也是可以自定义做一些分外的事情的,好比让tomcat容器住手,让dubbo服务下线等。

而这种自定义JVM清算动作的方式,是通过JDK中提供的shutdown hook实现的。JDK提供了Java.Runtime.addShutdownHook(Thread hook)方式,可以注册一个JVM关闭的钩子。

例子如下:

package com.hollis;

public class ShutdownHookTest {

    public static void main(String[] args) {
        boolean flag = true;
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("hook execute...");
        }));

        while (flag) {
            // app is runing
        }

        System.out.println("main thread execute end...");
    }
}

执行下令:

 jps
6520 ShutdownHookTest
6521 Jps
 kill 6520

控制台输出内容:

hook execute...
Process finished with exit code 143 (interrupted by signal 15: SIGTERM)

可以看到,当我们使用kill(默认kill -15)关闭历程的时刻,程序会先执行我注册的shutdownHook,然后再退出,并且会给出一个提醒:interrupted by signal 15: SIGTERM

若是我们执行下令kill -9

 kill -9 6520

控制台输出内容:

Process finished with exit code 137 (interrupted by signal 9: SIGKILL)

可以看到,当我们使用kill -9 强制关闭历程的时刻,程序并没有执行shutdownHook,而是直接退出了,并且会给出一个提醒:interrupted by signal 9: SIGKILL

总结

kill下令用于终止Linux历程,默认情况下,若是不指定信号,kill 等价于kill -15

kill -15执行时,系统向对应的程序发送SIGTERM(15)信号,该信号是可以被执行、壅闭和忽略的,以是应用程序接收到信号后,可以做一些准备工作,再举行程序终止。

有的时刻,kill -15无法终止程序,由于他可能被忽略,这时刻可以使用kill -9,系统会发出SIGKILL(9)信号,该信号不允许忽略和壅闭,以是应用程序会立刻终止。

这也会带来许多副作用,如数据丢失等,以是,在非必要时,不要使用kill -9下令,尤其是那些web应用、提供RPC服务、执行准时义务、包罗长事务等应用中,由于kill -9 没给spring容器、tomcat服务器、dubbo服务、流程引擎、状态机等足够的时间举行收尾。

最后,许多人会说,说了这么多,不是还得用 kill -9 吗?

实在,本文的目的不是不让人人用,那就是因噎废食了。本文是希望人人可以领会其背后的原理,知道他可能带来的副作用。在选择要不要执行的时刻,可以考虑到这些因素,若是能够针对可能发生的副作用,提前做好预案和心理准备,然后再执行,那就很完美了。

在执行之后,发生了非预期的问题时,人人可以想到有可能和kill -9有关,那本文的目的也算达到了。

迎接关注我的民众号,带给你更多避坑指南.

原创文章,作者:2d28新闻网,如若转载,请注明出处:https://www.2d28.com/archives/9083.html