什么叫优雅停机?

向应用进程发出停止指令之后,能保证正在执行的业务操作不受影响,直到操作运行完毕之后再停止服务。应用程序接收到停止指令之后,会进行如下操作:

1、停止接收新的访问请求
2、正在处理的请求,等待请求处理完毕;对于内部正在执行的其他任务,比如定时任务、mq 消费等等,也要等当前正在执行的任务执行完毕,并且不再启动新的任务
3、当应用准备关闭的时候,按需向外发出信号,告知其他应用服务准备接手,以保证服务高可用

方式一

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

常用的信号如下:

HUP 1 终端断线
INT 2 中断(同 Ctrl + C)
QUIT 3 退出(同 Ctrl + \)
TERM 15 终止
KILL 9 强制终止
CONT 18 继续(与STOP相反, fg/bg命令)
STOP 19 暂停(同 Ctrl + Z)

kill -9 和 kill -15 的区别?

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

当使用kill -15时,系统会发送一个终止的信号给对应的程序。当程序接收到该信号后,具体要如何处理是自己可以决定的。这时候,应用程序可以选择:

1、立即停止程序
2、释放响应资源后停止程序
3、忽略该信号,继续执行程序

因为kill -15信号只是通知对应的进程要进行”安全、干净的退出”,程序接到信号之后,退出前一般会进行一些”准备工作”,如资源释放、临时文件清理等等,如果准备工作做完了,再进行程序的终止。
但是,如果在”准备工作”进行过程中,遇到阻塞或者其他问题导致无法成功,那么应用程序可以选择忽略该终止信号。

和 kill -15相比,kill -9就相对强硬一点,系统会发出SIGKILL信号,他要求接收到该信号的程序应该立即结束运行,不能被阻塞或者忽略但这通常会带来一些副作用,数据丢失或者终端无法恢复到正常状态等。

方式二

这里没有使用Actuator方法来进行关闭,Actuator太复杂。

/**
* 服务关闭
*/
@RequestMapping("/shutdown")
public void shutdown() {
    try {
        // 这里最好加一个密码判断,把密码写入yml里面
        System.exit(0);
    } catch (Exception e) {
        LOGGER.error("shutdown:{}", e);
    }
}

方式三

通过 ConfigurableApplicationContext

@Autowired
private ConfigurableApplicationContext applicationContext;
/**
* 服务关闭
*/
@RequestMapping("/shutdown")
public void shutdown() {
    try {
        // 这里最好加一个密码判断,把密码写入yml里面
        applicationContext.close();
    } catch (Exception e) {
        LOGGER.error("shutdown:{}", e);
    }
}