先说不优雅的停机我们在ide中启动服务以后,比如说eclipse一般关闭的时候会直接点击红点关闭,如下图所示。在服务器上,也可能会使用kill -9 命令直接干掉服务,那么这样就是不优雅的停机,粗暴滴很!
那么问题来了,优雅和不优雅是怎么区别的呢?
在直接粗暴的杀掉服务时,可能有的业务逻辑还在执行,有的请求正在处理,内存等资源还未释放,直接就给干停了,不优雅。那如果通常通过注册JDK的ShutdownHook来实现,当系统接收到退出指令后,首先标记系统处于退出状态,不再接收新的消息,然后将积压的消息处理完,最后调用资源回收接口将资源销毁,最后各线程退出执行,这样正常关闭就优雅的很啦!
Jetty、Reactor Netty、Tomcat 和 Undertow四个嵌入式 Web 服务器以及反应式和基于Servlet的Web应用程序都支持正常关闭。
不允许新请求的确切方式因正在使用的 Web 服务器而异,Jetty、Reactor Netty 和 Tomcat 将停止接受网络层的请求。而Undertow 将接受请求,但会立即以服务不可用 (503) 响应进行响应。
通常优雅的退出需要有超时控制机制,例如30S,如果到达超时时间仍然没有完成退出前的资源回收等操作,则由停机脚本直接调用kill -9 pid,强制退出。
packagecom.xing.studyboot.listener.server; importjava.util.concurrent.Executor; importjava.util.concurrent.ThreadPoolExecutor; importjava.util.concurrent.TimeUnit; importorg.apache.catalina.connector.Connector; importorg.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer; importorg.springframework.context.ApplicationListener; importorg.springframework.context.event.ContextClosedEvent; publicclassGracefulShutdownimplementsApplicationListener<ContextClosedEvent>, TomcatConnectorCustomizer { privatevolatileConnectorconnector; intshutdownTimeout=30; publicvoidonApplicationEvent(ContextClosedEventevent) { this.connector.pause(); Executorexecutor=this.connector.getProtocolHandler().getExecutor(); if (executorinstanceofThreadPoolExecutor) { ThreadPoolExecutorthreadPoolExecutor= (ThreadPoolExecutor) executor; threadPoolExecutor.shutdown(); try { if (threadPoolExecutor.awaitTermination(shutdownTimeout, TimeUnit.SECONDS)) { System.out.println("Tomcat thread pool did not shutdown gracefully within "+shutdownTimeout+" seconds. Proceeding with forceful shutdown."); } } catch (InterruptedExceptione) { Thread.currentThread().interrupt(); } } System.out.println("线程池->优雅停机"); } publicvoidcustomize(Connectorconnector) { this.connector=connector; } }
配置:
packagecom.xing.studyboot.config.server; importorg.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; importorg.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importcom.xing.studyboot.listener.server.GracefulShutdown; publicclassShutDownConfig { publicGracefulShutdowngetShutdownPreDestroyBean() { returnnewGracefulShutdown(); } // @Bean// public ConfigurableServletWebServerFactory webServerFactory(GracefulShutdown gracefulShutdown) {// TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();// factory.addConnectorCustomizers(gracefulShutdown);// System.out.println("TomcatServletWebServerFactory->优雅停机");// return factory;// }}
我们使用上文配置的actuator中的shutdown来实现控制关机,
#启用shutdownmanagement.endpoint.shutdown.enabled=true
可以发现请求类型不对哈,换post请求:
看控制台:
总结:
想着可以写一个线程等待来测试下的,不想写了,以后会有管理员功能来更好的实现关机管控,了解为主。
还有配置没测试下效果,有兴趣可以试试:
server.shutdown=graceful要配置超时时间,请配置该spring.lifecycle.timeout-per-shutdown-phase属性,如以下示例所示:spring.lifecycle.timeout-per-shutdown-phase=20s
END