<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:你知道Dubbo怎么做優(yōu)雅上下線的嗎?你:優(yōu)雅上下線是啥?

          共 6331字,需瀏覽 13分鐘

           ·

          2021-04-23 22:18

          △Hollis, 一個對Coding有著獨特追求的人△
          這是Hollis的第 350 篇原創(chuàng)分享
          作者 l Hollis
          來源 l Hollis(ID:hollischuang)
          最近無論是校招還是社招,都進(jìn)行的如火如荼,我也承擔(dān)了很多的面試工作,在一次面試過程中,和候選人聊了一些關(guān)于Dubbo的知識。
          Dubbo是一個比較著名的RPC框架,很多人對于他的一些網(wǎng)絡(luò)通信、通信協(xié)議、動態(tài)代理等等都有一定的了解,這位候選人也一樣。
          但是,我接下來問了他一個問題:你們在使用Dubbo的時候,應(yīng)用如果重啟,怎么保證一個請求不會被中斷處理的呢?
          他沒怎么說的上來,我以為他不理解我的問題,我接著問他:我就是想問下Dubbo是如何做優(yōu)雅上下線的你知道嗎?
          接著他問我:優(yōu)雅上下線是啥??
          好吧。
          這篇文章,我來介紹一下這個知識點吧。



          優(yōu)雅上下線
          關(guān)于"優(yōu)雅上下線"這個詞,我沒找到官方的解釋,我嘗試解釋一下這是什么。
          首先,上線、下線大家一定都很清楚,比如我們一次應(yīng)用發(fā)布過程中,就需要先將應(yīng)用服務(wù)停掉,然后再把服務(wù)啟動起來。這個過程就包含了一次下線和一次上線。
          那么,"優(yōu)雅"怎么理解呢?
          先說什么情況我們認(rèn)為不優(yōu)雅:
          1、服務(wù)停止時,沒有關(guān)閉對應(yīng)的監(jiān)控,導(dǎo)致應(yīng)用停止后發(fā)生大量報警。
          2、應(yīng)用停止時,沒有通知外部調(diào)用方,很多請求還會過來,導(dǎo)致很多調(diào)用失敗。
          3、應(yīng)用停止時,有線程正在執(zhí)行中,執(zhí)行了一半,JVM進(jìn)程就被干掉了。
          4、應(yīng)用啟動時,服務(wù)還沒準(zhǔn)備好,就開始對外提供服務(wù),導(dǎo)致很多失敗調(diào)用。
          5、應(yīng)用啟動時,沒有檢查應(yīng)用的健康狀態(tài),就開始對外提供服務(wù),導(dǎo)致很多失敗調(diào)用。
          以上,都是我們認(rèn)為的不優(yōu)雅的情況,那么,反過來,優(yōu)雅上下線就是一種避免上述情況發(fā)生的手段。
          一個應(yīng)用的優(yōu)雅上下線涉及到的內(nèi)容其實有很多,從底層的操作系統(tǒng)、容器層面,到編程語言、框架層面,再到應(yīng)用架構(gòu)層面,涉及到的知識很廣泛。
          其實,優(yōu)雅上下線中,最重要的還是優(yōu)雅下線。因為如果下線過程不優(yōu)雅的話,就會發(fā)生很多調(diào)用失敗了、服務(wù)找不到等問題。所以很多時候,大家也會提優(yōu)雅停機(jī)這樣的概念。
          本文后面介紹的優(yōu)雅上下線也重點關(guān)注優(yōu)雅停機(jī)的過程。



          操作系統(tǒng)&容器的優(yōu)雅上下線
          關(guān)于操作系統(tǒng),我之前有一篇文章專門介紹過這個話題,可能大家沒有注意到,那時候介紹的主題是為什么不能在線上機(jī)器中隨便執(zhí)行kill -9
          其實,這背后的思考就是優(yōu)雅上下線。
          我們知道,kill -9之所以不建議使用,是因為kill -9特別強(qiáng)硬,系統(tǒng)會發(fā)出SIGKILL信號,他要求接收到該信號的程序應(yīng)該立即結(jié)束運行,不能被阻塞或者忽略。
          這個過程顯然是不優(yōu)雅的,因為應(yīng)用立刻停止的話,就沒辦法做收尾動作。而更優(yōu)雅的方式是kill -15。
          當(dāng)使用kill -15時,系統(tǒng)會發(fā)送一個SIGTERM的信號給對應(yīng)的程序。當(dāng)程序接收到該信號后,具體要如何處理是自己可以決定的。
          kill -15會通知到應(yīng)用程序,這就是操作系統(tǒng)對于優(yōu)雅上下線的最基本的支持。
          以前,在操作系統(tǒng)之上就是應(yīng)用程序了,但是,自從容器化技術(shù)推出之后,在操作系統(tǒng)和應(yīng)用程序之間,多了一個容器層,而Docker、k8s等容器其實也是支持優(yōu)雅上下線的。
          如Docker中同樣提供了兩個命令, docker stopdocker kill
          docker stop就像kill -15一樣,他會向容器內(nèi)的進(jìn)程發(fā)送SIGTERM信號,在10S之后(可通過參數(shù)指定)再發(fā)送SIGKILL信號。
          docker kill就像kill -9,直接發(fā)送SIGKILL信號。





          JVM的優(yōu)雅上下線
          在操作系統(tǒng)、容器等對優(yōu)雅上下線有了基本的支持之后,在接收到docker stop、kill -15等命令后,會通知應(yīng)用進(jìn)程進(jìn)行進(jìn)程關(guān)閉。
          而Java應(yīng)用在運行時就是一個獨立運行的進(jìn)程,這個進(jìn)程是如何關(guān)閉的呢?
          Java程序的終止運行是基于JVM的關(guān)閉實現(xiàn)的,JVM關(guān)閉方式分為正常關(guān)閉、強(qiáng)制關(guān)閉和異常關(guān)閉3種。
          這其中,正常關(guān)閉就是支持優(yōu)雅上下線的。正常關(guān)閉過程中,JVM可以做一些清理動作,比如刪除臨時文件。
          當(dāng)然,開發(fā)者也是可以自定義做一些額外的事情的,比如通知應(yīng)用框架優(yōu)雅上下線操作。
          而這種機(jī)制是通過JDK中提供的shutdown hook實現(xiàn)的。JDK提供了Java.Runtime.addShutdownHook(Thread hook)方法,可以注冊一個JVM關(guān)閉的鉤子。
          例子如下:

          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...");

                  }

              }

          執(zhí)行命令:

          jps
          6520 ShutdownHookTest
          6521 Jps
          kill 6520

          控制臺輸出內(nèi)容:

           hook execute...

           Process finished with exit code 143 (interrupted by signal 15: SIGTERM)

          可以看到,當(dāng)我們使用kill(默認(rèn)kill -15)關(guān)閉進(jìn)程的時候,程序會先執(zhí)行我注冊的shutdownHook,然后再退出,并且會給出一個提示:interrupted by signal 15: SIGTERM



          Spring的優(yōu)雅上下線
          有了JVM提供的shutdown hook之后,很多框架都可以通過這個機(jī)制來做優(yōu)雅下線的支持。
          比如Spring,他就會向JVM注冊一個shutdown hook,在接收到關(guān)閉通知的時候,進(jìn)行bean的銷毀,容器的銷毀處理等操作。
          同時,作為一個成熟的框架,Spring也提供了事件機(jī)制,可以借助這個機(jī)制實現(xiàn)更多的優(yōu)雅上下線功能。
          ApplicationListener是Spring事件機(jī)制的一部分,與抽象類ApplicationEvent類配合來完成ApplicationContext的事件機(jī)制。
          開發(fā)者可以實現(xiàn)ApplicationListener接口,監(jiān)聽到 Spring 容器的關(guān)閉事件(ContextClosedEvent),來做一些特殊的處理:

           @Component

              public class MyListener implements ApplicationListener<ContextClosedEvent{

                  @Override

                  public void onApplicationEvent(ContextClosedEvent event) {

                      // 做容器關(guān)閉之前的清理工作

                  }

              }




          Dubbo的優(yōu)雅上下線
          因為Spring中提供了ApplicationListener接口,幫助我們來監(jiān)聽容器關(guān)閉事件,那么,很多web容器、框架等就可以借助這個機(jī)制來做自己的優(yōu)雅上下線操作。
          如tomcat、dubbo等都是這么做的。
          這里簡答說一下Dubbo的,在Dubbo的官網(wǎng)中,有關(guān)于優(yōu)雅停機(jī)的介紹:

          應(yīng)用在停機(jī)時,接收到關(guān)閉通知時,會先把自己標(biāo)記為不接受(發(fā)起)新請求,然后再等待10s(默認(rèn)是10秒)的時候,等執(zhí)行中的線程執(zhí)行完。

          那么,之所以他能做這些事,是因為從操作系統(tǒng)、到JVM、到Spring等都對優(yōu)雅停機(jī)做了很好的支持。
          關(guān)于Dubbo各個版本中具體是如何借助JVM的shutdown hook機(jī)制、或者說Spring的事件機(jī)制的優(yōu)雅停機(jī),我的一位同事的一篇文章介紹的很清晰,大家可以看下:
          https://www.cnkirito.moe/dubbo-gracefully-shutdown/
          在從Dubbo 2.5 到 Dubbo 2.7介紹了歷史版本中,Dubbo為了解決優(yōu)雅上下線問題所遇到的問題和方案。
          目前,Dubbo中實現(xiàn)方式如下,同樣是用到了Spring的事件機(jī)制:

             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);

                  }

              }



          總結(jié)
          本文從操作系統(tǒng)開始,分別介紹了Linux、Docker、JVM、Spring、Dubbo等對優(yōu)雅停機(jī)的支持。
          可以看到,一個簡單的優(yōu)雅停機(jī)功能,上下游需要這么多底層基礎(chǔ)設(shè)施和上層應(yīng)用的支持。
          相信通過學(xué)習(xí)本文,你一定對優(yōu)雅上下線有了更多的了解。
          除此之外,我還希望你,通過本文以后,遇到一些實際問題的時候,可以想到文中提到的shutdown hook機(jī)制、Spring的event機(jī)制。很多時候,這些機(jī)制都能幫助我們解決很多問題。
          我在工作中,就有很多次使用過這樣的機(jī)制的實例,后面有機(jī)會給大家介紹幾個實例。
          好了,本文的全部內(nèi)容就是這么多啦,如果對你有幫助,記得一鍵三連哦~

          參考 :

          https://zhuanlan.zhihu.com/p/29093407

          https://www.cnkirito.moe/dubbo-gracefully-shutdown/

          推薦閱讀:

          Kafka原理篇:圖解kakfa架構(gòu)原理

          架構(gòu)設(shè)計方法論

          從面試角度一文學(xué)完 Kafka

          數(shù)據(jù)庫跟緩存的雙寫一致性


          關(guān)互聯(lián)網(wǎng)全棧架構(gòu)

          瀏覽 38
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  插B综合网 | 国产网站污 | 亚洲网站在线播放 | 午夜干美女 | 国产精品久久久久久无码红治院 |