面试官:SpringBoot怎么高雅停机?

高雅停机(Graceful Shutdown) 是指在服务器需求封闭或重启时,能够先处理完当时正在进行的恳求,然后再中止服务的操作。

高雅停机的完成步骤主要分为以下几步:

  1. 中止接收新的恳求:首要,体系会中止承受新的恳求,这样就不会有新的使命被添加到使命行列中。
  2. 处理当时恳求:体系会持续处理当时已经在处理中的恳求,确保这些恳求能够正常完结。这一般涉及到等待正在执行的使命完结,如处理HTTP恳求、数据库操作等。
  3. 开释资源:在恳求处理完结后,体系会开释一切已分配的资源,如封闭数据库连接、断开网络连接等。
  4. 封闭服务:最终,当一切恳求都处理完毕且资源都已开释后,体系会安全地封闭服务。

0.SpringBoot怎么完成高雅停机?

高雅停机的完成步骤分为以下两步:

  1. 运用合理的 kill 指令,给 Spring Boot 项目发送高雅停机指令。
  2. 敞开 Spring Boot 高雅停机/自定义 Spring Boot 高雅停机的完成。

1.合理杀死进程

在 Linux 中 kill 杀死进程的常用指令有以下这些:

  1. kill -2 pid:向指定 pid 发送 SIGINT 中止信号,等同于 ctrl+c。也就说,不仅当时进程会收到该信号,而且它的子进程也会收到停止的指令。
  2. kill -9 pid:向指定 pid 发送 SIGKILL 立即停止信号。程序不能捕获该信号,最粗犷最快速完毕程序的方法。
  3. kill -15 pid:向指定 pid 发送 SIGTERM 停止信号。信号会被当时进程接收到,但它的子进程不会收到,如果当时进程被 kill 掉,它的的子进程的父进程将变成 init 进程 (init 进程是那个 pid 为 1 的进程)。
  4. kill pid:等同于 kill 15 pid。

因而,在以上指令中,我们不能运用“kill -9”来杀死进程,运用“kill”杀死进程即可

2.设置SpringBoot高雅停机

在 Spring Boot 2.3.0 之后,能够通过装备设置敞开 Spring Boot 的高雅停机功用,如下所示:

# 敞开高雅停机,默认值:immediate 为立即封闭
server.shutdown=graceful
# 设置缓冲期,最大等待时间,默认:30秒
spring.lifecycle.timeout-per-shutdown-phase=60s

此刻,应用在封闭时,Web 服务器将不再承受新恳求,并等待正在进行的恳求完结的缓冲时间。

但是,如果是 Spring Boot 2.3.0 之前,就需求自行扩展(线程池)来完成高雅停机了。它的核心完成完成是在体系封闭时会调用 ShutdownHook,然后在 ShutdownHook 中阻塞 Web 容器的线程池,直到一切恳求都处理完毕再封闭程序,这样就完成自定义高雅线下了。

但是,不同的 Web 容器(Tomcat、Jetty、Undertow)有不同的自定义高雅停机的方法,以 Tomcat 为例,它的自定义高雅停机完成如下。

2.1 Tomcat 容器封闭代码

public class TomcatGracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {
    private volatile Connector connector;
    public void customize(Connector connector) {
        this.connector = connector;
    }
    public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
        this.connector.pause();
        Executor executor = this.connector.getProtocolHandler().getExecutor();
        if (executor instanceof ThreadPoolExecutor) {
            try {
                log.info("Start to shutdown tomcat thread pool");
                ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
                threadPoolExecutor.shutdown();
                if (!threadPoolExecutor.awaitTermination(20, TimeUnit.SECONDS)) {
                    log.warn("Tomcat thread pool did not shutdown gracefully within 20 seconds. ");
                }
            } catch (InterruptedException e) {
                log.warn("Fail to shut down tomcat thread pool ", e);
            }
        }
    }
}

2.2 设置 Tomcat 自动装配

@Configuration
@ConditionalOnClass({Servlet.class, Tomcat.class})
public static class TomcatConfiguration {
    @Bean
    public TomcatGracefulShutdown tomcatGracefulShutdown() {
        return new TomcatGracefulShutdown();
    }
    @Bean
    public EmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory(TomcatGracefulShutdown gracefulShutdown) {
        TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
        tomcatFactory.addConnectorCustomizers(gracefulShutdown);
        return tomcatFactory;
    }
}

课后考虑

Spring Boot Actuator 能完成高雅停机吗?为什么?怎么完成分布式体系的高雅停机?

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息行列等模块。