dubbo優雅停止

23221 ワード

サービスプロバイダが停止した場合、新しいリクエストを受信しないとマークし、新しいリクエストが来たときに直接エラーを報告し、クライアントに他のマシンを再試行させる.次に、スレッドプール内のスレッドが実行されているかどうかを検出し、タイムアウトしない限り、すべてのスレッドの実行が完了するまで待機します.サービス消費者が停止すると、新しい呼び出し要求は開始されず、すべての新しい呼び出しはクライアントでエラーが発生します.その後、リクエストの有無を検出した応答はまだ返されず、タイムアウトしない限り強制的に閉じられます.
ここではまずフックプログラムとは何かを説明します.Javaプログラムでは、閉じるフックを追加することで、プログラムが終了したときにリソースを閉じ、スムーズに終了する機能を実現することができます.Runtimeを使う.addShutdownHook(Thread hook)メソッドでは、JVMが閉じたフックを登録できます.このフックは、以下のシーンで呼び出すことができます.
  • プログラム正常終了
  • はSystemを用いる.exit()
  • 端末は、Ctrl+Cを使用するトリガされた割り込み
  • を使用する.
  • システムは
  • を閉じる
  • Kill pidコマンドを使用してプロセス
  • を終了
    私たちはRuntime.getRuntime().addShutdownHook()を通じてフックを登録して、ApplicationShutdownHooks.add(hook)に呼び出されて、最後にHOOKSというIdentityHashMapに保存されていることを発見しました.それはいつフックプログラムをトリガーしたのですか.ApplicationShutdownHooksには静的ブロックがありました
        static {
            try {
                Shutdown.add(1 /* shutdown hook invocation order */, false /* not registered if shutdown in progress */, new Runnable() { public void run() { runHooks(); } } ); hooks = new IdentityHashMap<>(); } catch (IllegalStateException e) { hooks = null; } } 

    最終的にはrunHooksメソッドが呼び出されます.System.exit()を確認しますが、最終的にはShutDown.exit()->sequence()を通じて入ってきて、runHooksを呼び出してフックプログラムを呼び出します.Javaはどのようにkill命令に応答したのでしょうか.SignalHandlerによって実現され、openjdkのwindowsディレクトリとsolarisディレクトリの下にTerminator.javaというコードがあります.
        SignalHandler sh = new SignalHandler() { public void handle(Signal sig) { Shutdown.exit(sig.getNumber() + 0200); } }; Signal.handle(new Signal("HUP"), sh); Signal.handle(new Signal("INT"), sh); Signal.handle(new Signal("TERM"), sh); 

    最後に、void* oldHandler = os::signal(sig, newHandler)によってlinuxシステムのsignal信号が取得される.
    振り返ってdubboを見ると、優雅なダウンタイムのタイムアウト時間を設定できます.デフォルトのタイムアウト時間は10秒です.(タイムアウトは強制的に閉じます)
    <dubbo:application ...> <dubbo:parameter key="shutdown.timeout" value="60000" />  dubbo:application> 

    サービス側フックプログラムを見てみましょう.
      Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { public void run() { if (logger.isInfoEnabled()) { logger.info("Run shutdown hook now."); } ProtocolConfig.destroyAll(); } }, "DubboShutdownHook")); 

    その結果、ProtocolConfig.destroyAll()メソッドが呼び出されました.
        public static void destroyAll() { AbstractRegistryFactory.destroyAll(); ExtensionLoader<Protocol> loader = ExtensionLoader.getExtensionLoader(Protocol.class); for (String protocolName : loader.getLoadedExtensions()) { try { Protocol protocol = loader.getLoadedExtension(protocolName); if (protocol != null) { protocol.destroy(); } } catch (Throwable t) { logger.warn(t.getMessage(), t); } } } 

    すべてのProtocolプロトコルをロードし、destroyメソッドをループして呼び出します.次に、DubboProtocoldestroyメソッドを見てみましょう.
        public void destroy() { for (String key : new ArrayList<String>(serverMap.keySet())) { ExchangeServer server = serverMap.remove(key); if (server != null) { try { if (logger.isInfoEnabled()) { logger.info("Close dubbo server: " + server.getLocalAddress()); } server.close(getServerShutdownTimeout()); } catch (Throwable t) { logger.warn(t.getMessage(), t); } } } for (String key : new ArrayList<String>(referenceClientMap.keySet())) { ExchangeClient client = referenceClientMap.remove(key); if (client != null) { try { if (logger.isInfoEnabled()) { logger.info("Close dubbo connect: " + client.getLocalAddress() + "-->" + client.getRemoteAddress()); } client.close(); } catch (Throwable t) { logger.warn(t.getMessage(), t); } } } for (String key : new ArrayList<String>(ghostClientMap.keySet())) { ExchangeClient client = ghostClientMap.remove(key); if (client != null) { try { if (logger.isInfoEnabled()) { logger.info("Close dubbo connect: " + client.getLocalAddress() + "-->" + client.getRemoteAddress()); } client.close(); } catch (Throwable t) { logger.warn(t.getMessage(), t); } } } stubServiceMethodsMap.clear(); super.destroy(); } 
  • serverは、サービス側がDubboProtocolopenServerを介してNettyを介してサービスを開始するため、serverMap.put(key, createServer(url))を閉じる.閉じるときは、ポートとシステムリソースを解放するために、サービスを閉じる必要があります.
  • reference client共有リンクを閉じ、ReferenceCountExchangeClient
  • ghost client(公式注釈では幽霊client)を閉じるこの操作は、プログラムバグがclientを誤って閉じることを防止するための防御措置
  • にすぎない.
  • クリアstubメソッドMap
  • suer.destroyはInvokerを閉じ、サービスを利用できないように設定します.そしてExporterを通ります.Uniexport()エクスポートされたサービスを閉じる
  • 作者:jerrik
    リンク:https://www.jianshu.com/p/6e4d1ecb0815
    出典:簡書
    著作権は作者の所有である.商業転載は著者に連絡して許可を得てください.非商業転載は出典を明記してください.