技術共有

DangerWind-RPC フレームワーク ---3. サーバーのシャットダウン

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

マシンがオフラインになると、多くの問題に直面します。登録センターからマシンをオフラインにするにはどうすればよいでしょうか?リソースをクリーンアップして解放するにはどうすればよいですか?クライアントは、サービス リストを取得するときにローカル キャッシュも使用します。ローカル キャッシュを適時に更新するにはどうすればよいですか?

サーバー マシンを正常にシャットダウンするには、ShutdownHook を使用する必要があります。これは、シャットダウン フックを追加するのと同じです。このフックは、JVM のシャットダウン時 (つまり、プログラムの終了時) に呼び出され、リソースとクリーンアップを行うスレッドです。正常にシャットダウンします。

  1. public void clearAll() {
  2. log.info("addShutdownHook for clearAll");
  3. // 添加了一个关闭钩子,这个钩子是一个线程,它在JVM关闭时(即程序结束时)被调用,清理资源,优雅下机
  4. Runtime.getRuntime().addShutdownHook(new Thread(() -> {
  5. try {
  6. InetSocketAddress inetSocketAddress = new InetSocketAddress(InetAddress.getLocalHost().getHostAddress(), NettyRpcServer.PORT);
  7. CuratorUtils.clearRegistry(CuratorUtils.getZkClient(), inetSocketAddress);
  8. } catch (UnknownHostException ignored) {
  9. }
  10. // 操作完整、优雅,便于释放连接资源,便于自定义清理逻辑
  11. ThreadPoolFactoryUtil.shutDownAllThreadPool();
  12. }));
  13. }

フック スレッドでは、以下に示すように、登録センターからノードを削除するロジックを記述する必要があります。

  1. // RPC Server端 本机所注册服务的缓存
  2. private static final Set<String> REGISTERED_PATH_SET = ConcurrentHashMap.newKeySet();
  3. public static void clearRegistry(CuratorFramework zkClient, InetSocketAddress inetSocketAddress) {
  4. REGISTERED_PATH_SET.stream().parallel().forEach(p -> {
  5. try {
  6. // 是本机在ZK注册的节点
  7. if (p.endsWith(inetSocketAddress.toString())) {
  8. // 根据路径名删除节点
  9. zkClient.delete().forPath(p);
  10. }
  11. } catch (Exception e) {
  12. log.error("clear registry for path [{}] fail", p);
  13. }
  14. });
  15. log.info("All registered services on the server are cleared:[{}]", REGISTERED_PATH_SET.toString());
  16. }

登録センター ZK でノードを削除した後、スレッド プール リソースを解放する必要があります。

  1. public static void shutDownAllThreadPool() {
  2. log.info("call shutDownAllThreadPool method");
  3. THREAD_POOLS.entrySet().parallelStream().forEach(entry -> {
  4. ExecutorService executorService = entry.getValue();
  5. // 停止接收新的任务,但已提交的任务会继续执行
  6. executorService.shutdown();
  7. log.info("shut down thread pool [{}] [{}]", entry.getKey(), executorService.isTerminated());
  8. try {
  9. // 等待线程池中的任务在指定的时间内完成。如果在指定时间内线程池未能终止,会抛出 InterruptedException
  10. executorService.awaitTermination(10, TimeUnit.SECONDS);
  11. } catch (InterruptedException e) {
  12. log.error("Thread pool never terminated");
  13. // 指定时间内线程池未能终止,立即停止所有正在执行的任务
  14. executorService.shutdownNow();
  15. }
  16. });
  17. }

スレッド プールを閉じるロジックをカスタマイズすることで、よりエレガントにスレッド プール リソースの解放を実現できます。新しいタスクの受け付けを停止し、一定の待機時間内に送信されたタスクの実行を継続することができます。待機時間を超えると、スレッド プールは強制的に終了されます。