成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

別再用 kill -9 了,這才是微服務(wù)上下線的正確姿勢(shì)!

開發(fā) 后端
就上線來說,如果組件或者容器沒有啟動(dòng)成功,就不應(yīng)該對(duì)外暴露服務(wù),對(duì)于下線來說,如果機(jī)器已經(jīng)停機(jī)了,就應(yīng)該保證服務(wù)已下線,如此可避免上游流量進(jìn)入不健康的機(jī)器。

 對(duì)于微服務(wù)來說,服務(wù)的優(yōu)雅上下線是必要的。

就上線來說,如果組件或者容器沒有啟動(dòng)成功,就不應(yīng)該對(duì)外暴露服務(wù),對(duì)于下線來說,如果機(jī)器已經(jīng)停機(jī)了,就應(yīng)該保證服務(wù)已下線,如此可避免上游流量進(jìn)入不健康的機(jī)器。

優(yōu)雅下線

基礎(chǔ)下線(Spring/SpringBoot/內(nèi)置容器)

首先JVM本身是支持通過shutdownHook的方式優(yōu)雅停機(jī)的。 

  1. Runtime.getRuntime().addShutdownHook(new Thread() {  
  2.     @Override  
  3.     public void run() {  
  4.         close();  
  5.     }  
  6. }); 

此方式支持在以下幾種場(chǎng)景優(yōu)雅停機(jī):

程序正常退出

使用System.exit()

終端使用Ctrl+C

使用Kill pid干掉進(jìn)程

那么如果你偏偏要kill -9 程序肯定是不知所措的。

而在Springboot中,其實(shí)已經(jīng)幫你實(shí)現(xiàn)好了一個(gè)shutdownHook,支持響應(yīng)Ctrl+c或者kill -15 TERM信號(hào)。

隨便啟動(dòng)一個(gè)應(yīng)用,然后Ctrl+c一下,觀察日志就可知, 它在 AnnotationConfigEmbeddedWebApplicationContext 這個(gè)類中打印出了疑似Closing...的日志,真正的實(shí)現(xiàn)邏輯在其父類 AbstractApplicationContext 中(這個(gè)其實(shí)是spring中的類,意味著什么呢,在spring中就支持了對(duì)優(yōu)雅停機(jī)的擴(kuò)展)。

Spring Boot 系列教程和示例源碼看這里:https://github.com/javastacks/spring-boot-best-practice 

  1. public void registerShutdownHook() {  
  2.     if (this.shutdownHook == null) {  
  3.         this.shutdownHook = new Thread() {  
  4.             public void run() {  
  5.                 synchronized(AbstractApplicationContext.this.startupShutdownMonitor) {  
  6.                     AbstractApplicationContext.this.doClose();  
  7.                 }  
  8.             }  
  9.         };  
  10.         Runtime.getRuntime().addShutdownHook(this.shutdownHook);  
  11.     } 
  12.  
  13. public void destroy() {  
  14.     this.close();  
  15.  
  16. public void close() {  
  17.     Object var1 = this.startupShutdownMonitor; 
  18.      synchronized(this.startupShutdownMonitor) { 
  19.          this.doClose();  
  20.         if (this.shutdownHook != null) {  
  21.             try {  
  22.                 Runtime.getRuntime().removeShutdownHook(this.shutdownHook);  
  23.             } catch (IllegalStateException var4) {  
  24.                 ;  
  25.             }  
  26.         }  
  27.     }  
  28.  
  29. protected void doClose() {  
  30.     if (this.active.get() && this.closed.compareAndSet(false, true)) {  
  31.         if (this.logger.isInfoEnabled()) {  
  32.             this.logger.info("Closing " + this);  
  33.         }  
  34.         LiveBeansView.unregisterApplicationContext(this);  
  35.         try {  
  36.             this.publishEvent((ApplicationEvent)(new ContextClosedEvent(this)));  
  37.         } catch (Throwable var3) {  
  38.             this.logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", var3);  
  39.         }  
  40.         if (this.lifecycleProcessor != null) {  
  41.             try {  
  42.                 this.lifecycleProcessor.onClose();  
  43.             } catch (Throwable var2) {  
  44.                 this.logger.warn("Exception thrown from LifecycleProcessor on context close", var2);  
  45.             }  
  46.         }  
  47.         this.destroyBeans();  
  48.         this.closeBeanFactory();  
  49.         this.onClose();  
  50.         this.active.set(false);  
  51.     }   

我們能對(duì)它做些什么呢,其實(shí)很明顯,在doClose方法中它發(fā)布了一個(gè)ContextClosedEvent的方法,不就是給我們擴(kuò)展用的么。

于是我們可以寫個(gè)監(jiān)聽器監(jiān)聽ContextClosedEvent,在發(fā)生事件的時(shí)候做下線邏輯,對(duì)微服務(wù)來說即是從注冊(cè)中心中注銷掉服務(wù)。 

  1. @Component  
  2. public class GracefulShutdownListener implements ApplicationListener<ContextClosedEvent> {  
  3.         @Override  
  4.     public void onApplicationEvent(ContextClosedEvent contextClosedEvent){  
  5.        //注銷邏輯  
  6.        zookeeperRegistry.unregister(mCurrentServiceURL);  
  7.        ...  
  8.     }  

可能會(huì)有疑問的是,微服務(wù)中一般來說,注銷服務(wù)往往是優(yōu)雅下線的第一步,接著才會(huì)執(zhí)行停機(jī)操作,那么這個(gè)時(shí)候流量進(jìn)來怎么辦呢?

個(gè)人會(huì)建議是,在注銷服務(wù)之后就可開啟請(qǐng)求擋板拒絕流量了,通過微服務(wù)框架本身的故障轉(zhuǎn)移功能去處理被拒絕的流量即可。另外,關(guān)注公眾號(hào)Java技術(shù)棧,在后臺(tái)回復(fù):面試,可以獲取我整理的 Java、Spring Boot 系列面試題和答案,非常齊全。

Docker中的下線

好有人說了,我用docker部署服務(wù),支不支持優(yōu)雅下線。

那來看看docker的一些停止命令都會(huì)干些啥:

一般來說,正常人可能會(huì)用docker stop或者docker kill 命令去關(guān)閉容器(當(dāng)然如果上一步注冊(cè)了USR2自定義信息,可能會(huì)通過docker exec kill -12去關(guān)閉)。

對(duì)于docker stop來說,它會(huì)發(fā)一個(gè)SIGTERM(kill -15 term信息)給容器的PID1進(jìn)程,并且默認(rèn)會(huì)等待10s,再發(fā)送一個(gè)SIGKILL(kill -9 信息)給PID1。

那么很明顯,docker stop允許程序有個(gè)默認(rèn)10s的反應(yīng)時(shí)間去做一下優(yōu)雅停機(jī)的操作,程序只要能對(duì)kill -15 信號(hào)做些反應(yīng)就好了,如上一步描述。那么這是比較良好的方式。

當(dāng)然如果shutdownHook方法執(zhí)行了個(gè)50s,那肯定不優(yōu)雅了。可以通過docker stop -t 加上等待時(shí)間。

外置容器的shutdown腳本(Jetty)

如果非要用外置容器方式部署(個(gè)人認(rèn)為浪費(fèi)資源并提升復(fù)雜度)。那么能不能優(yōu)雅停機(jī)呢。

可以當(dāng)然也是可以的,這里有兩種方式:

首先RPC框架本身提供優(yōu)雅上下線接口,以供調(diào)用來結(jié)束整個(gè)應(yīng)用的生命周期,并且提供擴(kuò)展點(diǎn)供開發(fā)者自定義服務(wù)下線自身的停機(jī)邏輯。同時(shí)調(diào)用該接口的操作會(huì)封裝成一個(gè)preStop操作固化在jetty或者其他容器的shutdown腳本中,保證在容器停止之前先調(diào)用下線接口結(jié)束掉整個(gè)應(yīng)用的生命周期。shutdown腳本中執(zhí)行類發(fā)起下線服務(wù) -> 關(guān)閉端口 -> 檢查下線服務(wù)直至完成 -> 關(guān)閉容器的流程。

而更簡(jiǎn)單的另一種方法是直接在腳本中加入kill -15命令。

優(yōu)雅上線

優(yōu)雅上線相對(duì)來說可能會(huì)更加困難一些,因?yàn)闆]有什么默認(rèn)的實(shí)現(xiàn)方式,但是總之呢,一個(gè)原則就是確保端口存在之后才上線服務(wù)。

springboot內(nèi)置容器優(yōu)雅上線

這個(gè)就很簡(jiǎn)單了,并且業(yè)界在應(yīng)用層面的優(yōu)雅上線均是在內(nèi)置容器的前提下實(shí)現(xiàn)的,并且還可以配合一些列健康檢查做文章。Spring Boot 優(yōu)雅關(guān)閉新姿勢(shì),看看這篇。

參看sofa-boot的健康檢查的源碼,它會(huì)在程序啟動(dòng)的時(shí)候先對(duì)springboot的組件做一些健康檢查,然后再對(duì)它自己搞得sofa的一些中間件做健康檢查,整個(gè)健康檢查的流程完畢之后(sofaboot 目前是沒法對(duì)自身應(yīng)用層面做健康檢查的,它有寫相關(guān)接口,但是寫死了port is ready...)才會(huì)暴露服務(wù)或者說優(yōu)雅上線,那么它健康檢查的時(shí)機(jī)是什么時(shí)候呢: 

  1. @Override  
  2. public void onApplicationEvent(ContextRefreshedEvent event) {  
  3.     healthCheckerProcessor.init();  
  4.     healthIndicatorProcessor.init();  
  5.     afterHealthCheckCallbackProcessor.init();  
  6.     publishBeforeHealthCheckEvent();  
  7.     readinessHealthCheck();  

可以看到它是監(jiān)聽了ContextRefreshedEvent這個(gè)事件。在內(nèi)置容器模式中,內(nèi)置容器模式的start方法是在refreshContext方法中,方法執(zhí)行完成之后發(fā)布一個(gè)ContextRefreshedEvent事件,也就是說在監(jiān)聽到這個(gè)事件的時(shí)候,內(nèi)置容器必然是啟動(dòng)成功了的。

但ContextRefreshedEvent這個(gè)事件,在一些特定場(chǎng)景中由于種種原因,ContextRefreshedEvent會(huì)被監(jiān)聽到多次,沒有辦法保證當(dāng)前是最后一次event,從而正確執(zhí)行優(yōu)雅上線邏輯。

在springboot中還有一個(gè)更加靠后的事件,叫做ApplicationReadyEvent,它的發(fā)布藏在了afterRefresh還要后面的那一句listeners.finished(context, null)中,完完全全可以保證內(nèi)置容器 端口已經(jīng)存在了,所以我們可以監(jiān)聽這個(gè)事件去做優(yōu)雅上線的邏輯,甚至可以把中間件相關(guān)的健康檢查集成在這里。 

  1. @Component  
  2. public class GracefulStartupListener implements ApplicationListener<ApplicationReadyEvent> {      
  3.     @Override  
  4.     public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent){  
  5.        //注冊(cè)邏輯 優(yōu)雅上線  
  6.        apiRegister.register(urls);  
  7.        ...  
  8.     }  

外置容器(Jetty)優(yōu)雅上線

目前大多數(shù)應(yīng)用的部署模式不管是jetty部署模式還是docker部署模式(同樣使用jetty鏡像),本質(zhì)上用的都是外置容器。那么這個(gè)情況就比較困難了,至少在應(yīng)用層面無法觀察到外部容器的運(yùn)行狀態(tài),并且容器本身沒有提供什么hook給你實(shí)現(xiàn)。

那么和優(yōu)雅上線一樣,需要RPC框架提供優(yōu)雅上線接口來初始化整個(gè)應(yīng)用的生命周期,并且提供擴(kuò)展點(diǎn)給開發(fā)者供執(zhí)行自定義的上線邏輯(上報(bào)版本探測(cè)信息等)。同樣將調(diào)用這個(gè)接口封裝成一個(gè)postStart操作,固化在jetty等外置容器的startup腳本中,保證應(yīng)用在容器啟動(dòng)之后在上線。容器執(zhí)行類似啟動(dòng)容器 -> 健康檢查 -> 上線服務(wù)邏輯 -> 健康上線服務(wù)直至完成 的流程。

 

 

責(zé)任編輯:龐桂玉 來源: Java技術(shù)棧
相關(guān)推薦

2025-01-10 06:30:00

2021-05-25 09:30:44

kill -9Linux kill -9 pid

2024-09-25 08:22:06

2019-01-02 10:49:54

Tomcat內(nèi)存HotSpot VM

2021-11-05 10:36:19

性能優(yōu)化實(shí)踐

2020-08-05 07:27:54

SQL優(yōu)化分類

2023-10-26 16:33:59

float 布局前段CSS

2019-06-27 17:18:02

Java日志編程語言

2024-12-26 07:47:20

2020-06-28 16:28:24

Windows 10WindowsU盤

2017-06-12 16:17:07

2018-07-30 11:21:30

華為云

2025-01-15 12:31:46

2021-05-26 05:33:30

5G網(wǎng)絡(luò)運(yùn)營商

2024-09-09 11:11:45

2025-04-25 10:28:40

2025-05-19 04:00:00

2025-03-12 11:14:45

2020-12-04 10:05:00

Pythonprint代碼

2020-12-02 11:18:50

print調(diào)試代碼Python
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日批免费在线观看 | 欧美精品一区二区蜜桃 | 欧美国产日韩在线 | 国产精品av久久久久久久久久 | 天天艹逼网 | 亚洲九色| 精品一区在线免费观看 | 日韩在线小视频 | 久久精品国产99国产精品亚洲 | 天天爽综合网 | 欧美精品一区二区在线观看 | 欧美一区不卡 | 国产日韩欧美中文 | 欧美日韩一区二区三区四区五区 | 日本免费在线 | 一区二区不卡视频 | 久久久久久久香蕉 | 国产欧美一区二区三区在线看 | 久久久久久国产精品 | 一区二区三区在线 | 欧 | 午夜免费视频 | 精品国产一区二区国模嫣然 | 午夜寂寞影院在线观看 | 久久久久久国产精品免费免费 | 亚洲成人一区二区三区 | 伊人天堂网 | 综合色在线 | 国产精品毛片一区二区在线看 | 日韩在线观看中文字幕 | 超碰在线网站 | 久久成人精品视频 | 成人影院在线视频 | 99亚洲精品 | 精品一区二区三区免费视频 | 欧美精三区欧美精三区 | 国产精品资源在线 | 这里只有精品99re | 影音先锋欧美资源 | 一级片免费网站 | 午夜小电影 | 欧美日韩中文字幕 |