Новые функции Spring Boot 2.3, элегантное завершение работы, подробное объяснение

Java

Эта статья является оригинальной статьей. Любая форма перепечатки приветствуется, но обязательно с указанием источникаЛенг Ленг https://lltx.github.io.

Что такое изящное завершение работы

Начнем с простого кода, а именно:

@RestController
public class DemoController {
	@GetMapping("/demo")
	public String demo() throws InterruptedException {
	    // 模拟业务耗时处理流程
		Thread.sleep(20 * 1000L);
		return "hello";
	}
}

Когда наш трафик запрашивает этот интерфейс для выполнения бизнес-логики, если сервер в это время выполняет завершение работы (kill), spring boot по умолчанию напрямую отключает контейнер (tomcat и т. д.), что приводит к сбою выполнения этой бизнес-логики. . В некоторых бизнес-сценариях: будут несогласованности данных, и логика транзакций не будет откатана.

graceful shutdown

В последней версии spring boot 2.3 эта функция встроена, и для ее обработки нет необходимости расширять пул потоков контейнера. В настоящее время встроенные поддерживаемые веб-серверы Spring Boot (Jetty, Reactor Netty, Tomcat и Undertow), а также реактивные веб-приложения и веб-приложения на основе сервлетов поддерживают плавное завершение работы. Давайте посмотрим, как использовать:

когда используешьserver.shutdown=gracefulЕсли этот параметр включен, при завершении работы веб-контейнера веб-сервер больше не будет получать новые запросы и будет ждать буферного периода для завершения активных запросов.

Опыт настройки

Поддерживаемое здесь поведение завершения работы, давайте посмотрим на перечисление исходного кода следующим образом:
/**
 * Configuration for shutting down a {@link WebServer}.
 *
 * @author Andy Wilkinson
 * @since 2.3.0
 */
public enum Shutdown {
	/**
	 * 优雅停机 (限期停机)
	 *
	 */
	GRACEFUL,

	/**
	 * 立即停机
	 */
	IMMEDIATE;

}
буферный периодtimeout-per-shutdown-phaseнастроить
  • Время по умолчанию 30 с, что означает максимальное время ожидания 30 с. Тайм-аут будет остановлен независимо от того, выполняется ли задача потока или нет. Он должен быть установлен разумно и разумно.

Опыт эффекта

    1. интерфейс сервера запросов
    1. выполнить закрытие приложения
    1. Сервер получает команду выключения
2020-05-17 18:28:28.940  INFO 60341 --- [extShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown        : Commencing graceful shutdown. Waiting for active requests to complete
2020-05-17 18:28:45.923  INFO 60341 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown        : Graceful shutdown complete
    1. Выполнение запроса интерфейса завершено

связанная информация

  1. о казни здесьkill -2вместоkill -9
  • kill -2 эквивалентен сочетанию клавиш Ctrl + C, которое запускает обработку событий Java ShutdownHook (для корректного завершения работы или некоторой постобработки обратитесь к следующему исходному коду)
//ApplicationContext
	@Override
	public void registerShutdownHook() {
		if (this.shutdownHook == null) {
			// No shutdown hook registered yet.
			this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
				@Override
				public void run() {
					synchronized (startupShutdownMonitor) {
						doClose();
					}
				}
			};
			Runtime.getRuntime().addShutdownHook(this.shutdownHook);
		}
	}
  • kill -9, насильственная эстетика принудительно завершает процесс, ShutdownHook не выполняется
  1. Мягкое завершение работы с активацией конечных точек

POST-запрос/actuator/shutdownМожет быть выполнено изящное завершение работы.

Анализ исходного кода

@Endpoint(id = "shutdown", enableByDefault = false)
public class ShutdownEndpoint implements ApplicationContextAware {

	@WriteOperation
	public Map<String, String> shutdown() {
		Thread thread = new Thread(this::performShutdown);
		thread.setContextClassLoader(getClass().getClassLoader());
		thread.start();
	}

	private void performShutdown() {
		try {
			Thread.sleep(500L);
		}
		catch (InterruptedException ex) {
			Thread.currentThread().interrupt();
		}

		// 此处close 逻辑和上边 shutdownhook 的处理一样
		this.context.close();
	}
}
  1. Различия в корректном завершении работы различных веб-контейнеров

Поведение контейнера во время простоя зависит от конкретного поведения веб-контейнера.

имя веб-контейнера заявление о поведении
tomcat 9.0.33+ Перестать получать запросы, клиент ждет тайм-аут для новых запросов.
Reactor Netty Перестать получать запросы, клиент ждет тайм-аут для новых запросов.
Undertow Перестаньте получать запросы, и клиент напрямую вернет 503 для новых запросов.