기술나눔

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

스레드 풀을 닫는 논리를 사용자 정의하면 스레드 풀 리소스의 해제를 보다 우아하게 실현할 수 있습니다. 특정 대기 시간 내에 새로운 작업 수락을 중단하고 제출된 작업을 계속 실행할 수 있습니다. 대기 시간이 초과되면 스레드 풀이 강제 종료됩니다.