tomcat Sping Boot 优雅关机

58wvjzkj  于 8个月前  发布在  其他
关注(0)|答案(3)|浏览(71)

我正在开发一个由嵌入式Tomcat支持的Sping Boot 应用程序,我需要通过以下步骤开发一个优雅的关机:
1.停止处理新的HTTP请求(停止Web容器)
1.处理所有已接受的请求

  1. shutdown Spring ApplicationContext
  • 按顺序执行上述步骤(一个接一个)

我如何才能做到这一点?
P.S. Sping Boot 1.5.20.RELEASE,Java 8

mo49yndu

mo49yndu1#

Sping Boot 2.3(2020年5月发布)中添加了优雅关闭支持。这允许活动请求在关闭上下文和关闭容器之前完成。
当启用优雅关机时,应用程序将在关机时按顺序执行以下步骤:

  • 停止接受新请求
  • 将等待一些 * 可配置 * 时间来处理已接受的请求
  • 停止容器
  • 停止嵌入式服务器

来自Release Notes:
所有四个嵌入式Web服务器(Jetty、Reactor Netty、Tomcat和Undertow)以及React式和基于Servlet的Web应用程序都支持优雅关闭。当使用server.shutdown=graceful启用时,在关闭时,Web服务器将不再允许新请求,并将等待宽限期以完成活动请求。可以使用spring.lifecycle.timeout-per-shutdown-phase配置宽限期。

  • 要启用优雅关闭,请将server.shutdown=graceful添加到属性(默认情况下设置为immediate)。
  • 可以使用spring.lifecycle.timeout-per-shutdown-phase属性配置宽限期(例如:spring.lifecycle.timeout-per-shutdown-phase=1m

对于< 2.3的Sping Boot ,您需要修改服务器的连接器以停止接受新请求,如this Spring GitHub issue中所述。

vatpfxk5

vatpfxk52#

我最终得到了:

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.catalina.connector.Connector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;

public class GracefulShutdown implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {

  private static final Logger log = LoggerFactory.getLogger(GracefulShutdown.class);
  private volatile Connector connector;

  @Override
  public void customize(Connector connector) {
    this.connector = connector;
  }

  @Override
  public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
    log.info("Protocol handler is shutting down");

    this.connector.pause();
    Executor executor = this.connector.getProtocolHandler().getExecutor();
    if (executor instanceof ThreadPoolExecutor) {
      try {
        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
        threadPoolExecutor.shutdown();

        if (!threadPoolExecutor.awaitTermination(30, TimeUnit.SECONDS))
          log.warn("Tomcat thread pool did not shut down gracefully within 30 seconds. Proceeding with forceful shutdown");
        else
          log.info("Protocol handler shut down");

      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
      }
    }
  }
}

更多的豆:

import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
...
  @Bean
  public GracefulShutdown gracefulShutdown() {
    return new GracefulShutdown();
  }

  @Bean
  public EmbeddedServletContainerFactory servletContainer(final GracefulShutdown gracefulShutdown) {
    TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
    factory.addConnectorCustomizers(gracefulShutdown);
    return factory;
  }
...
7uhlpewt

7uhlpewt3#

它的简单,Spring Boot 本身提供的功能。https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-application-exit

void shoutdown(){
       System.out.println("====+= Shoutdown +++===");
       System.exit(SpringApplication.exit(apc, this.exitCodeGenerator()));
      
   }

在输出中可以看到,所有当前线程都被关闭。输出量:
=+= Shoutdown +==

2020-06-09 11:21:45,543
DEBUG[main][c.u.j.c.EnableEncryptablePropertiesBeanFactoryPostProcessor]
Application Event Raised: ExitCodeEvent  2020-06-09 11:21:45,543
DEBUG[main][c.u.j.c.EnableEncryptablePropertiesBeanFactoryPostProcessor]
Application Event Raised: ExitCodeEvent  2020-06-09 11:21:45,546
DEBUG[main][c.u.j.c.EnableEncryptablePropertiesBeanFactoryPostProcessor]
Application Event Raised: ContextClosedEvent  2020-06-09 11:21:45,546
DEBUG[main][c.u.j.c.EnableEncryptablePropertiesBeanFactoryPostProcessor]
Application Event Raised: ContextClosedEvent  2020-06-09 11:21:45,547
INFO [main][o.a.kafka.clients.producer.KafkaProducer] [Producer
clientId=producer-1] Closing the Kafka producer with timeoutMillis =
30000 ms.  2020-06-09 11:21:45,548
DEBUG[kafka-producer-network-thread |
producer-1][o.a.k.clients.producer.internals.Sender] [Producer
clientId=producer-1] Beginning shutdown of Kafka producer I/O thread,
sending remaining records.  2020-06-09 11:21:45,551
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name connections-closed:  2020-06-09 11:21:45,554
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name connections-created:  2020-06-09 11:21:45,554
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name successful-authentication:  2020-06-09 11:21:45,558
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name failed-authentication:  2020-06-09 11:21:45,558
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name bytes-sent-received:  2020-06-09 11:21:45,559
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name bytes-sent:  2020-06-09 11:21:45,559
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name bytes-received:  2020-06-09 11:21:45,560
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name select-time:  2020-06-09 11:21:45,561
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name io-time:  2020-06-09 11:21:45,570
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name node--1.bytes-sent  2020-06-09 11:21:45,570
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name node--1.bytes-received  2020-06-09 11:21:45,570
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name node--1.latency  2020-06-09 11:21:45,571
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name node-0.bytes-sent  2020-06-09 11:21:45,571
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name node-0.bytes-received  2020-06-09 11:21:45,573
DEBUG[kafka-producer-network-thread |
producer-1][org.apache.kafka.common.metrics.Metrics] Removed sensor
with name node-0.latency  2020-06-09 11:21:45,573
DEBUG[kafka-producer-network-thread |
producer-1][o.a.k.clients.producer.internals.Sender] [Producer
clientId=producer-1] Shutdown of Kafka producer I/O thread has
completed.  2020-06-09 11:21:45,607
DEBUG[main][o.a.kafka.clients.producer.KafkaProducer] [Producer
clientId=producer-1] Kafka producer has been closed  2020-06-09
11:21:45,611 DEBUG[main][o.hibernate.internal.SessionFactoryImpl]
HHH000031: Closing  2020-06-09 11:21:45,611
DEBUG[main][o.h.type.spi.TypeConfiguration$Scope] Un-scoping
TypeConfiguration
[org.hibernate.type.spi.TypeConfiguration$Scope@5dfd31f4] from
SessionFactory [org.hibernate.internal.SessionFactoryImpl@62a54948] 
2020-06-09 11:21:45,612
DEBUG[main][o.h.s.i.AbstractServiceRegistryImpl] Implicitly
destroying ServiceRegistry on de-registration of all child
ServiceRegistries  2020-06-09 11:21:45,613
DEBUG[main][o.h.b.r.i.BootstrapServiceRegistryImpl] Implicitly
destroying Boot-strap registry on de-registration of all child
ServiceRegistries  2020-06-09 11:21:45,613 INFO
[main][com.zaxxer.hikari.HikariDataSource] HikariPool-1 - Shutdown
initiated...  2020-06-09 11:21:45,754 INFO
[main][com.zaxxer.hikari.HikariDataSource] HikariPool-1 - Shutdown
completed.

相关问题