Spring Boot 优雅停机
发布网友
发布时间:2024-10-22 00:18
我来回答
共1个回答
热心网友
时间:2024-10-22 00:54
所谓优雅停机,指的是在接收到停止指令后,应用进程能确保当前正在处理的业务操作不受影响,直至完成。具体步骤是停止接收新请求,等待现有请求处理完毕并成功返回后才真正终止。Java生态下,底层技术支持实现了在Java语言上各Web容器的优雅停机。
Linux环境中的`kill`命令负责终止进程,通过后跟数字实现信号编号的发送。`kill -l`可以列出所有信号编号,`kill -9 pid`强制性杀死进程,`kill -15 pid`发送通知应用主动关闭,`ctrl+c`操作则相当于`kill -2 pid`,用于通知前台进程终止。
以Jar包形式运行应用,使用`kill -15 pid`或`ctrl+c`,而`kill -9 pid`命令无任何输出。应用中关键在于`Runtime.class`和`ApplicationShutdownHooks.class`,`Shutdown.add`方法执行Runnable任务,通过`ApplicationShutdownHooks`类和`DeleteOnExitHook`类存放关闭前处理线程。Spring Boot通过`SpringApplication`注册关闭钩子。
实现优雅停机的关键在于正确处理请求和线程管理。以Tomcat作为servlet容器为例,实现`LifecycleListener`接口并获取Connector,监听Spring的关闭事件。对于`connector.pause()`执行后,应用仍可接受新请求,直至线程池被shutdown后返回`connection peer`。较好的做法是在低流量时段进行滚动部署,将流量导入一部分实例,关闭其余实例并部署新服务,确认无误后再切换流量。
线程何时退出由线程自身决定。使用`Thread.interrupt`方法将线程设置为中断状态。如果线程处于阻塞状态(如`wait`方法或IO等待),会立即退出并抛出`InterruptedException`异常。如果线程处于运行状态,中断状态仅被设置,线程通过`isInterrupted`方法检查自己是否被中断来决定是否退出。
线程池提供`shutdownNow`和`shutdown`方法。`shutdownNow`拒绝接收新任务,立即关闭线程池,未执行的任务不再执行。`shutdown`同样拒绝接收新任务,等待现有任务执行完毕后关闭线程池。`advanceRunState(STOP)`将线程池状态设置为`STOP`,`interruptWorkers()`中断所有工作线程,`tasks = drainQueue()`移除队列中的未执行任务并返回。
`shutdownNow`后,线程池的反应是当任务处于运行状态时不受中断影响继续执行,但阻塞状态时会抛出`InterruptedException`导致循环结束。当`getTask`方法返回`null`时,循环同样结束。由于`shutdownNow`将状态设为`STOP`,线程池将在循环中返回`null`,从而退出。
`shutdown`方法将线程池状态设为`SHUTDOWN`,空闲线程的中断标志被设置。线程退出的依据是`getTask`方法返回`null`,这表示队列为空。在`getTask`方法的`if`判断中,由于线程池已修改为`SHUTDOWN`状态,只有当队列为空时,`getTask`才会返回`null`,从而使得线程退出。
总结而言,优雅停机的核心在于正确管理请求和线程,确保正在处理的业务不受影响直至完成。通过合理的部署策略、线程池管理和中断机制,实现应用的平滑关闭。最后,使用`awaitTermination`方法确保线程池完全关闭,需要等待调用此方法以阻塞等待线程池关闭。