樓主目前就職于某互聯(lián)網(wǎng)公司,也在傳統(tǒng)金融公司呆過,看過身邊很多同事發(fā)布的時(shí)候都是直接kill -9 pid,場面一度十分粗魯,然而這樣會(huì)有什么問題嗎?這樣在項(xiàng)目啟動(dòng)的時(shí)候沒有注冊hook,會(huì)導(dǎo)致在項(xiàng)目重新發(fā)布的時(shí)候,如果已經(jīng)正在處理請求會(huì)被強(qiáng)制關(guān)閉,甚至導(dǎo)致異常,而且還沒有做補(bǔ)償機(jī)制.
背景:目前我們的服務(wù)都是集群的,發(fā)布的時(shí)候會(huì)一臺臺切過去,假如當(dāng)前有三個(gè)節(jié)點(diǎn),節(jié)點(diǎn)正準(zhǔn)備發(fā)布了,首先腳本了會(huì)執(zhí)行調(diào)用stop命令去關(guān)閉當(dāng)前服務(wù)的進(jìn)程,這個(gè)時(shí)候首先服務(wù)應(yīng)該踢出集群,如果有新請求進(jìn)來,負(fù)載策略會(huì)把當(dāng)前新的請求打到節(jié)點(diǎn)二或者節(jié)點(diǎn)三上面,節(jié)點(diǎn)一不在接收新的請求了,繼續(xù)處理殘余的請求,對結(jié)束現(xiàn)場進(jìn)行清理,已保證現(xiàn)場.
慎用kill -9 pid(如果能保證當(dāng)前不會(huì)有請求進(jìn)來),或者當(dāng)前服務(wù)是一個(gè)批量任務(wù),那么可以忽略.
啟動(dòng)腳本init.script里面kill pid默認(rèn)是kill -15 pid,這個(gè)才是真正的去關(guān)閉進(jìn)程,當(dāng)用kill pid的時(shí)候,首先會(huì)發(fā)出interrupt的中斷指令,之前注冊過的hook監(jiān)聽到指令,線程池本身不在接收新的請求了,這個(gè)時(shí)候可以釋放線程池的資源,等當(dāng)前所以的線程都結(jié)束以后,才平滑的退出,這樣就可以保證服務(wù)不間斷,24小時(shí)不停服務(wù).
目前一下這些操作都會(huì)觸發(fā)shutdownhook
1)程序正常退出
2)使用System.exit()
3)終端使用Ctrl+C觸發(fā)的中斷
4)系統(tǒng)關(guān)閉
5)OutOfMemory宕機(jī)
6)使用Kill pid命令干掉進(jìn)程(注:在使用kill -9 pid時(shí),是不會(huì)被調(diào)用的)
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("當(dāng)前打印的數(shù)字是: " + i);
}
public static void test2() {
threadPool.shutdown();
while (!threadPool.isTerminated()) {
try {
System.out.println("還有線程沒有關(guān)閉");
TimeUnit.SECONDS.sleep(5);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("shut down!");
}
}
測試結(jié)果:
kill -9 57283
當(dāng)前打印的數(shù)字是: 1
當(dāng)前打印的數(shù)字是: 1
當(dāng)前打印的數(shù)字是: 1
當(dāng)前打印的數(shù)字是: 1
程序被強(qiáng)制結(jié)束了
kill 57542
當(dāng)前打印的數(shù)字是: 1
當(dāng)前打印的數(shù)字是: 1
當(dāng)前打印的數(shù)字是: 1
當(dāng)前打印的數(shù)字是: 1
當(dāng)前打印的數(shù)字是: 1
當(dāng)前打印的數(shù)字是: 1
當(dāng)前打印的數(shù)字是: 1
當(dāng)前打印的數(shù)字是: 1
還有線程沒有關(guān)閉
當(dāng)前打印的數(shù)字是: 1
當(dāng)前打印的數(shù)字是: 1
shut down!