最近無論是校招還是社招,都進行的如火如荼,我也承擔了很多的面試作業,在一次面試程序中,和候選人聊了一些關于Dubbo的知識,
Dubbo是一個比較著名的RPC框架,很多人對于他的一些網路通信、通信協議、動態代理等等都有一定的了解,這位候選人也一樣,
但是,我接下來問了他一個問題:你們在使用Dubbo的時候,應用如果重啟,怎么保證一個請求不會被中斷處理的呢?
他沒怎么說的上來,我以為他不理解我的問題,我接著問他:我就是想問下Dubbo是如何做優雅上下線的你知道嗎?
接著他問我:優雅上下線是啥??
好吧,
這篇文章,我來介紹一下這個知識點吧,
優雅上下線
關于"優雅上下線"這個詞,我沒找到官方的解釋,我嘗試解釋一下這是什么,
首先,上線、下線大家一定都很清楚,比如我們一次應用發布程序中,就需要先將應用服務停掉,然后再把服務啟動起來,這個過成就包含了一次下線和一次上線,
那么,"優雅"怎么理解呢?
先說什么情況我們認為不優雅:
1、服務停止時,沒有關閉對應的監控,導致應用停止后發生大量報警,
2、應用停止時,沒有通知外部呼叫方,很多請求還會過來,導致很多呼叫失敗,
3、應用停止時,有執行緒正在執行中,執行了一半,JVM行程就被干掉了,
4、應用啟動時,服務還沒準備好,就開始對外提供服務,導致很多失敗呼叫,
5、應用啟動時,沒有檢查應用的健康狀態,就開始對外提供服務,導致很多失敗呼叫,
以上,都是我們認為的不優雅的情況,那么,反過來,優雅上下線就是一種避免上述情況發生的手段,
一個應用的優雅上下線涉及到的內容其實有很多,從底層的作業系統、容器層面,到編程語言、框架層面,再到應用架構層面,涉及到的知識很廣泛,
其實,優雅上下線中,最重要的還是優雅下線,因為如果下執行緒序不優雅的話,就會發生很多呼叫失敗了、服務找不到等問題,所以很多時候,大家也會提優雅停機這樣的概念,
本文后面介紹的優雅上下線也重點關注優雅停機的程序,
作業系統&容器的優雅上下線
關于作業系統,我之前有一篇文章專門介紹過這個話題,可能大家沒有注意到,那時候介紹的主題是為什么不能在線上機器中隨便執行kill -9,
其實,這背后的思考就是優雅上下線,
我們知道,kill -9之所以不建議使用,是因為kill -9特別強硬,系統會發出SIGKILL信號,他要求接收到該信號的程式應該立即結束運行,不能被阻塞或者忽略,
這個程序顯然是不優雅的,因為應用立刻停止的話,就沒辦法做收尾動作,而更優雅的方式是kill -15,
當使用kill -15時,系統會發送一個SIGTERM的信號給對應的程式,當程式接收到該信號后,具體要如何處理是自己可以決定的,
kill -15會通知到應用程式,這就是作業系統對于優雅上下線的最基本的支持,
以前,在作業系統之上就是應用程式了,但是,自從容器化技術推出之后,在作業系統和應用程式之間,多了一個容器層,而Docker、k8s等容器其實也是支持優雅上下線的,
如Docker中同樣提供了兩個命令, docker stop 和 docker kill
docker stop就像kill -15一樣,他會向容器內的行程發送SIGTERM信號,在10S之后(可通過引數指定)再發送SIGKILL信號,
而docker kill就像kill -9,直接發送SIGKILL信號,
JVM的優雅上下線
在作業系統、容器等對優雅上下線有了基本的支持之后,在接收到docker stop、kill -15等命令后,會通知應用行程進行行程關閉,
而Java應用在運行時就是一個獨立運行的行程,這個行程是如何關閉的呢?
Java程式的終止運行是基于JVM的關閉實作的,JVM關閉方式分為正常關閉、強制關閉和例外關閉3種,
這其中,正常關閉就是支持優雅上下線的,正常關閉程序中,JVM可以做一些清理動作,比如洗掉臨時檔案,
當然,開發者也是可以自定義做一些額外的事情的,比如通知應用框架優雅上下線操作,
而這種機制是通過JDK中提供的shutdown hook實作的,JDK提供了Java.Runtime.addShutdownHook(Thread hook)方法,可以注冊一個JVM關閉的鉤子,
例子如下:
package com.hollis;
public class ShutdownHookTest {
public static void main(String[] args) {
boolean flag = true;
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("hook execute...");
}));
while (flag) {
// app is runing
}
System.out.println("main thread execute end...");
}
}
執行命令:
? jps
6520 ShutdownHookTest
6521 Jps
? kill 6520
控制臺輸出內容:
hook execute...
Process finished with exit code 143 (interrupted by signal 15: SIGTERM)
可以看到,當我們使用kill(默認kill -15)關閉行程的時候,程式會先執行我注冊的shutdownHook,然后再退出,并且會給出一個提示:interrupted by signal 15: SIGTERM
Spring的優雅上下線
有了JVM提供的shutdown hook之后,很多框架都可以通過這個機制來做優雅下線的支持,
比如Spring,他就會向JVM注冊一個shutdown hook,在接收到關閉通知的時候,進行bean的銷毀,容器的銷毀處理等操作,
同時,作為一個成熟的框架,Spring也提供了事件機制,可以借助這個機制實作更多的優雅上下線功能,
ApplicationListener是Spring事件機制的一部分,與抽象類ApplicationEvent類配合來完成ApplicationContext的事件機制,
開發者可以實作ApplicationListener介面,監聽到 Spring 容器的關閉事件(ContextClosedEvent),來做一些特殊的處理:
@Component
public class MyListener implements ApplicationListener<ContextClosedEvent> {
@Override
public void onApplicationEvent(ContextClosedEvent event) {
// 做容器關閉之前的清理作業
}
}
Dubbo的優雅上下線
因為Spring中提供了ApplicationListener介面,幫助我們來監聽容器關閉事件,那么,很多web容器、框架等就可以借助這個機制來做自己的優雅上下線操作,
如tomcat、dubbo等都是這么做的,
這里簡答說一下Dubbo的,在Dubbo的官網中,有關于優雅停機的介紹:

應用在停機時,接收到關閉通知時,會先把自己標記為不接受(發起)新請求,然后再等待10s(默認是10秒)的時候,等執行中的執行緒執行完,
那么,之所以他能做這些事,是因為從作業系統、到JVM、到Spring等都對優雅停機做了很好的支持,
關于Dubbo各個版本中具體是如何借助JVM的shutdown hook機制、或者說Spring的事件機制昨的優雅停機,我的一位同事的一篇文章介紹的很清晰,大家可以看下:
https://www.cnkirito.moe/dubbo-gracefully-shutdown/
在從Dubbo 2.5 到 Dubbo 2.7介紹了歷史版本中,Dubbo為了解決優雅上下線問題所遇到的問題和方案,
目前,Dubbo中實作方式如下,同樣是用到了Spring的事件機制:
public class SpringExtensionFactory implements ExtensionFactory {
public static void addApplicationContext(ApplicationContext context) {
CONTEXTS.add(context);
if (context instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) context).registerShutdownHook();
DubboShutdownHook.getDubboShutdownHook().unregister();
}
BeanFactoryUtils.addApplicationListener(context, SHUTDOWN_HOOK_LISTENER);
}
}
總結
本文從作業系統開始,分別介紹了Linux、Docker、JVM、Spring、Dubbo等對優雅停機的支持,
可以看到,一個簡單的優雅停機功能,上下游需要這么多底層基礎設施和上層應用的支持,
相信通過學習本文,你一定對優雅上下線有了更多的了解,
除此之外,我還希望你,通過本文以后,遇到一些實際問題的時候,可以想到文中提到的shutdown hook機制、Spring的event機制,很多時候,這些機制都能幫助我們解決很多問題,
我在作業中,就有很多次使用過這樣的機制的實體,后面有機會給大家介紹幾個實體,
參考 :
https://zhuanlan.zhihu.com/p/29093407
https://www.cnkirito.moe/dubbo-gracefully-shutdown/
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/278407.html
標籤:AI
