服务如何优雅的退出
楼主目前就职于某互联网公司,也在传统金融公司呆过,看过身边很多同事发布的时候都是直接kill -9 pid,场面一度十分粗鲁,然而这样会有什么问题吗?这样在项目启动的时候没有注册hook,会导致在项目重新发布的时候,如果已经正在处理请求会被强制关闭,甚至导致异常,而且还没有做补偿机制.
背景:
目前我们的服务都是集群的,发布的时候会一台台切过去,假如当前有三个节点,节点正准备发布了,首先脚本了会执行调用stop命令去关闭当前服务的进程,这个时候首先服务应该踢出集群,如果有新请求进来,负载策略会把当前新的请求打到节点二或者节点三上面,节点一不在接收新的请求了,继续处理残余的请求,对结束现场进行清理,已保证现场.
注意:
慎用kill -9 pid(如果能保证当前不会有请求进来),或者当前服务是一个批量任务,那么可以忽略.
启动脚本init.script里面kill pid默认是kill -15 pid,这个才是真正的去关闭进程,当用kill pid的时候,首先会发出interrupt的中断指令,之前注册过的hook监听到指令,线程池本身不在接收新的请求了,这个时候可以释放线程池的资源,等当前所以的线程都结束以后,才平滑的退出,这样就可以保证服务不间断,24小时不停服务.
目前一下这些操作都会触发shutdownhook
触发条件:
id | 场景描述 |
---|---|
1 | 程序正常退出 |
2 | 使用System.exit() |
3 | 终端使用Ctrl+C触发的中断 |
4 | 系统关闭 |
5 | OutOfMemory宕机 |
6 | 使用Kill pid命令干掉进程(注:在使用kill -9 pid时,是不会被调用的) |
下面以线程池为例
Demo:
package com.example.hook;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.concurrent.*;
import static java.lang.Thread.sleep;
@SpringBootApplication
public class HookApplication {
static ThreadPoolExecutorthreadPool =new ThreadPoolExecutor(2, 6, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(10), new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("reject ------");
}
});
public static void main(String[] args) {
SpringApplication.run(HookApplication.class, args);
Runtime.getRuntime().addShutdownHook(new Thread(() -> test2()));
for(int i=1;i<=10;i++){
threadPool.submit(() ->test1(1));
}
}
public static void test1(int i) {
try {
sleep(3000);
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前打印的数字是: " + i);
}
public static void test2() {
threadPool.shutdown();
while (!threadPool.isTerminated()) {
try {
System.out.println("还有线程没有关闭");
TimeUnit.SECONDS.sleep(5);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("shut down!");
}
}
测试结果:
kill -9 57283
当前打印的数字是: 1
当前打印的数字是: 1
当前打印的数字是: 1
当前打印的数字是: 1
程序被强制结束了
kill 57542
当前打印的数字是: 1
当前打印的数字是: 1
当前打印的数字是: 1
当前打印的数字是: 1
当前打印的数字是: 1
当前打印的数字是: 1
当前打印的数字是: 1
当前打印的数字是: 1
还有线程没有关闭
当前打印的数字是: 1
当前打印的数字是: 1
shut down!
网友评论