Partage de technologie

DangerWind-RPC-framework --- 3. Arrêt du serveur

2024-07-12

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

Lorsqu'une machine se déconnecte, elle est confrontée à de nombreux problèmes : Comment la mettre hors ligne depuis le centre d'enregistrement ? Comment nettoyer et libérer les ressources ? Le client utilise également le cache local lors de l'extraction de la liste de services. Comment mettre à jour le cache local à temps ?

L'arrêt progressif de la machine serveur nécessite l'utilisation de ShutdownHook, ce qui équivaut à l'ajout d'un hook d'arrêt. Ce hook est un thread qui est appelé lorsque la JVM est arrêtée (c'est-à-dire lorsque le programme se termine) pour nettoyer les ressources et. s'arrêter gracieusement.

  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. }

Dans le thread de hook, vous devez écrire la logique pour supprimer les nœuds du centre d'enregistrement, comme indiqué ci-dessous :

  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. }

Après avoir supprimé le nœud dans le centre d'enregistrement ZK, les ressources du pool de threads doivent être libérées :

  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. }

La personnalisation de la logique de fermeture du pool de threads peut réaliser la libération des ressources du pool de threads de manière plus élégante. Il peut cesser d'accepter de nouvelles tâches et continuer à exécuter les tâches soumises dans un certain délai d'attente. Si le temps d'attente est dépassé, le pool de threads est arrêté de force.