最近,公司项目优化重构,为了项目可以无缝上下线,如丝般顺滑,考虑到添加优雅停机功能。优雅停机包含线程池、消息、数据库、服务下线。
jvm有钩子函数在收到kill命令后会执行回掉,可以使用这个实现优雅下线。简单介绍一下kill命令。-2类似于ctrl+c,kill -15服务正常下线会触发jvm钩子函数。kill -9系统内核直接杀死,不会触发钩子函数。
优雅下线涉及到bean的生命周期销毁。ContextClosedEvent和@PreDestroy和周期和DisposableBean参考链接
https://blog.csdn.net/qq_4384...
线程池、mq、db等都在spring的bean销毁之前下线,注意下线顺序。例子:
相同方式可以通过@Order控制顺序
private ThreadPoolExecutor executor;
@Bean
@Primary
public ThreadPoolExecutor asyncServiceExecutor() {
executor = new ThreadPoolExecutor(5, 20, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
@PreDestroy
public void destroyThreadPool() {
if (!executor.isTerminated()){
executor.shutdown();
try {
executor.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
executor.shutdownNow();
}
}
log.info("ThreadPoolExecutor destroyed !");
}
dubbo下线
dubbo默认开启了优雅停机。下线分为从注册中心下线,关闭协议
2.7之后源码如下:ShutdownHookListener,继承 Spring ApplicationListener 接口,用以监听 Spring 相关事件。这里 ShutdownHookListener 仅仅监听 Spring 关闭事件,当 Spring 开始关闭,将会触发 ShutdownHookListener 内部逻辑
public class SpringExtensionFactory implements ExtensionFactory {
private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class);
private static final Set<ApplicationContext> CONTEXTS = new ConcurrentHashSet<ApplicationContext>();
private static final ApplicationListener SHUTDOWN_HOOK_LISTENER = new ShutdownHookListener();
public static void addApplicationContext(ApplicationContext context) {
CONTEXTS.add(context);
if (context instanceof ConfigurableApplicationContext) {
// 注册 ShutdownHook
((ConfigurableApplicationContext) context).registerShutdownHook();
// 取消 AbstractConfig 注册的 ShutdownHook 事件
DubboShutdownHook.getDubboShutdownHook().unregister();
}
BeanFactoryUtils.addApplicationListener(context, SHUTDOWN_HOOK_LISTENER);
}
// 继承 ApplicationListener,这个监听器将会监听容器关闭事件
private static class ShutdownHookListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextClosedEvent) {
DubboShutdownHook shutdownHook = DubboShutdownHook.getDubboShutdownHook();
shutdownHook.doDestroy();
}
}
}
}
通过配置dubbo.application.shutwait=30s可以设置dubbo等待时间
springboot下线
熟悉介绍springboot优雅停机,在Springboot2.3之前需要自己实现优雅停机。2.3后自己实现了优雅停机。
springboot2.3之前的实现方式。
1、创建SafetyShutDownConfig类实现TomcatConnectorCustomizer,ApplicationListener<ContextClosedEvent>接口即可,kill -2和kill -15就可以进行测试
@Slf4j
@Configuration
public class SafetyShutDownConfig implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {
private volatile Connector connector;
private final int waitTime = 30;
@Override
public void customize(Connector connector) {
this.connector = connector;
}
@Override
public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
this.connector.pause();
Executor executor = this.connector.getProtocolHandler().getExecutor();
if (executor instanceof ThreadPoolExecutor) {
try {
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
threadPoolExecutor.shutdown();
if (!threadPoolExecutor.awaitTermination(waitTime, TimeUnit.SECONDS)) {
log.warn("Tomcat thread pool did not shut down gracefully within " + waitTime + " seconds. Proceeding with forceful shutdown");
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
springboot2.3之后的实现
1、在配置文件中开启就可以
#开启优雅停机
server.shutdown=graceful
#优雅停机最大等待时间
spring.lifecycle.timeout-per-shutdown-phase=30s
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。