java中如何优雅的停止服务

2020-08-30  本文已影响0人  不怕天黑_0819

强制进程退出的副作用:

解决方法:

针对线程池的停机:
使用 DisposableBean 接口

public abstract class ExecutorConfigurationSupport extends CustomizableThreadFactory
      implements DisposableBean{
    @Override
    public void destroy() {
        shutdown();
    }

    /**
     * Perform a shutdown on the underlying ExecutorService.
     * @see java.util.concurrent.ExecutorService#shutdown()
     * @see java.util.concurrent.ExecutorService#shutdownNow()
     * @see #awaitTerminationIfNecessary()
     */
    public void shutdown() {
        if (this.waitForTasksToCompleteOnShutdown) {
            this.executor.shutdown();
        }
        else {
            this.executor.shutdownNow();
        }
        awaitTerminationIfNecessary();
    }

    /**
     * Wait for the executor to terminate, according to the value of the
     * {@link #setAwaitTerminationSeconds "awaitTerminationSeconds"} property.
     */
    private void awaitTerminationIfNecessary() {
        if (this.awaitTerminationSeconds > 0) {
            try {
                this.executor.awaitTermination(this.awaitTerminationSeconds, TimeUnit.SECONDS));
            }
            catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

1 通过 waitForTasksToCompleteOnShutdown 标志来控制是想立刻终止所有任务,还是等待任务执行完成后退出。

2 executor.awaitTermination(this.awaitTerminationSeconds, TimeUnit.SECONDS)); 控制等待的时间,防止任务无限期的运行(前面已经强调过了,即使是 shutdownNow 也不能保证线程一定停止运行)。

更多需要我们的思考的优雅停机策略

服务治理框架一般会考虑到优雅停机的问题。通常的做法是事先隔断流量,接着关闭应用。常见的做法是将服务节点从注册中心摘除,订阅者接收通知,移除节点,从而优雅停机;涉及到数据库操作,则可以使用事务的 ACID 特性来保证即使 crash 停机也能保证不出现异常数据,正常下线则更不用说了;又比如消息队列可以依靠 ACK 机制 + 消息持久化,或者是事务消息保障;定时任务较多的服务,处理下线则特别需要注意优雅停机的问题,因为这是一个长时间运行的服务,比其他情况更容易受停机问题的影响,可以使用幂等和标志位的方式来设计定时任务…

事务和 ACK 这类特性的支持,即使是宕机,停电,kill -9 pid 等情况,也可以使服务尽量可靠;而同样需要我们思考的还有 kill -15 pid,正常下线等情况下的停机策略。最后再补充下整理这个问题时,自己对 jvm shutdown hook 的一些理解。

shutdown hook 会保证 JVM 一直运行,直到 hook 终止 (terminated)。这也启示我们,如果接收到 kill -15 pid 命令时,执行阻塞操作,可以做到等待任务执行完成之后再关闭 JVM。同时,也解释了一些应用执行 kill -15 pid 无法退出的问题,没错,中断被阻塞了。

注:若需要平滑停止服务,我们一般可以通过ShutdownHook和Signal来实现。ShutdownHook一般比较难保证关闭任务的执行顺序,这个时候可以考虑使用Signal机制来完全托管我们关闭服务的执行顺序。

参考链接:
https://www.cnkirito.moe/gracefully-shutdown/

https://www.cnblogs.com/panchanggui/p/9806266.html

https://juejin.im/post/6844903814181421064

上一篇 下一篇

猜你喜欢

热点阅读