왜 프로그램 에 갑자기 200 개의 Dubbo-thread 스 레 드 가 추가 되 었 는 지 설명 합 니 다.

배경
프로그램 스 레 드 스 택 정 보 를 볼 때 200 개의 Dubbo-thread 스 레 드 가 있 고 대부분 WAITING 상태 에 있 습 니 다.다음 과 같 습 니 다.

"Dubbo-thread-200" #160932 daemon prio=5 os_prio=0 tid=0x00007f5af9b54800 nid=0x79a6 waiting on condition [0x00007f5a9acd5000]
  java.lang.Thread.State: WAITING (parking)
 at sun.misc.Unsafe.park(Native Method)
 - parking to wait for <0x00000000c78f1240> (a java.util.concurrent.SynchronousQueue$TransferStack)
 at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:458)
 at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
 at java.util.concurrent.SynchronousQueue.take(SynchronousQueue.java:924)
 at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
 at java.lang.Thread.run(Thread.java:748)

  Locked ownable synchronizers:
 - None
왜 이렇게 Dubbo-thread 라인 이 많 을까요?이 스 레 드 들 은 어떤 작용 을 합 니까?의문 을 가지 고 소스 코드 를 연구 했다.
소스 코드 분석
Dubbo(2.7.5 버 전)의 스 레 드 풀 은 네 가지 구체 적 인 실현 유형 이 있다.

fixed=org.apache.dubbo.common.threadpool.support.fixed.FixedThreadPool
cached=org.apache.dubbo.common.threadpool.support.cached.CachedThreadPool
limited=org.apache.dubbo.common.threadpool.support.limited.LimitedThreadPool
eager=org.apache.dubbo.common.threadpool.support.eager.EagerThreadPool
프로그램 은 구체 적 인 구현 클래스 의 getExecutor(URL url)방법 을 호출 하여 스 레 드 풀 을 만 듭 니 다.이 방법 을 호출 하 는 것 은 DefaultExecutor Repository 류 의 createExecutor 방법 뿐 입 니 다.이 방법 은 url 의 매개 변수 threadpool=cached 에 따라 그러한 유형의 스 레 드 풀 을 만 들 기로 결 정 됩 니 다.createExecutor 는 개인 적 인 방법 으로 다음 두 가지 방법 이 있 습 니 다.

 /**
   * Get called when the server or client instance initiating.
   *
   * @param url
   * @return
   */
  public synchronized ExecutorService createExecutorIfAbsent(URL url) {
    String componentKey = EXECUTOR_SERVICE_COMPONENT_KEY;
    if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {
      componentKey = CONSUMER_SIDE;
    }
    Map<Integer, ExecutorService> executors = data.computeIfAbsent(componentKey, k -> new ConcurrentHashMap<>());
    Integer portKey = url.getPort();
    ExecutorService executor = executors.computeIfAbsent(portKey, k -> createExecutor(url));
    // If executor has been shut down, create a new one
    if (executor.isShutdown() || executor.isTerminated()) {
      executors.remove(portKey);
      executor = createExecutor(url);
      executors.put(portKey, executor);
    }
    return executor;
  }

  public ExecutorService getExecutor(URL url) {
    String componentKey = EXECUTOR_SERVICE_COMPONENT_KEY;
    if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {
      componentKey = CONSUMER_SIDE;
    }
    Map<Integer, ExecutorService> executors = data.get(componentKey);

    /**
     * It's guaranteed that this method is called after {@link #createExecutorIfAbsent(URL)}, so data should already
     * have Executor instances generated and stored.
     */
    if (executors == null) {
      logger.warn("No available executors, this is not expected, framework should call createExecutorIfAbsent first " +
          "before coming to here.");
      return null;
    }

    Integer portKey = url.getPort();
    ExecutorService executor = executors.get(portKey);
    if (executor != null) {
      if (executor.isShutdown() || executor.isTerminated()) {
        executors.remove(portKey);
        executor = createExecutor(url);
        executors.put(portKey, executor);
      }
    }
    return executor;
  }
위의 첫 번 째 방법 에 대해 비 고 는 서비스 제공 자 나 서비스 소비자 가 초기 화 할 때 호출 된다 는 것 을 설명 했다.debug 를 통 해 알 수 있 듯 이 서비스 제공 자 초기 화 는 스 레 드 이름 이 DubboServer Handler-10.12.16.67:20880-thread 인 스 레 드 탱크 를 만 들 고 서비스 소비 자 는 스 레 드 이름 이 DubboClient Handler-10.12.16.67:20880-thread 인 스 레 드 탱크 를 만 들 것 이다.
Dubbo 가 만 든 스 레 드 탱크 는 Map 에 저장 되 어 공유 합 니 다.
private ConcurrentMap> data = new ConcurrentHashMap<>();
밖의 키 는 서비스 제공 자 또는 소비 자 를 나타 낸다.안의 키 는 서비스 가 노출 된 포트 번 호 를 나타 낸다.즉,소비 자 는 같은 포트 번호 의 서비스 에 대해 하나의 스 레 드 탱크 만 만 만 들 고 같은 스 레 드 탱크 를 공유 하여 서비스 요청 과 정 보 를 받 은 후에 일련의 처 리 를 한다.
Dubbo-thread 이름과 달리 두 번 째 방법 으로 만 든 스 레 드 풀 일 가능성 이 높다.두 번 째 방법의 호출 은 위로 거 슬러 올 라 가면 비교적 분산 되 어 유용 한 정 보 를 찾 을 수 없다.
방법 에 대한 구체 적 인 내용 을 보면 이미 만 든 스 레 드 풀 이 닫 히 거나 종 료 될 때 새로운 스 레 드 풀 을 다시 만 듭 니 다.그 다음 에 어떤 상황 에서 오프라인 스 레 드 가 닫 히 거나 종 료 될 지 추측 했다.서비스 가 재 개 된 후에 스 택 정 보 를 출력 하 는 데 Dubbo-thread 스 레 드 가 없 었 다.그 다음 에 소비 자 와 공급 자 연결 이 끊 기 면 스 레 드 탱크 가 닫 히 지 않 을 까 추측 하여 서비스 제공 자 를 재 개 했다.과연 Dubbo-thread 스 레 드 를 재현 했다.
그리고 Dubbo 의 구체 적 인 스 레 드 탱크 생 성 방법 에 로 그 를 추가 하고 스 택 정 보 를 출력 합 니 다(이상 출력 호출 정 보 를 생 성 합 니 다).
다음 그림:

여기에 그림 설명 을 삽입 하면 channel 이 효력 을 잃 었 을 때 disconnected 방법 을 호출 하고 최종 적 으로 DefaultExecutor Repository 류 의 getExecutor 를 호출 하여 스 레 드 풀 을 만 듭 니 다.서비스 제공 자가 다시 시작 할 때 소비 자 는 해당 스 레 드 풀 을 shutdown 합 니 다.
스 레 드 풀 을 만 드 는 데 사용 되 는 URL 을 재현 하 는 것 은 Wrapped Channel Handler 클래스 의 URL 입 니 다.이 값 은 서비스 시작 초기 화 에 설정 되 어 있 으 며,AbstractClient 클 라 이언 트 Executor 보다 일찍 설정 되 어 있 습 니 다.
따라서 channel 이 끊 겨 서 다시 만 든 스 레 드 풀 에 사용 되 는 URL 과 클 라 이언 트 가 스 레 드 풀 을 처음 만 드 는 데 사용 하 는 URL 은 다 를 수 있 습 니 다.특히 consumer 의 스 레 드 풀 형식 을 설정 하지 않 았 을 때 초기 에 만 든 Cached 형식 스 레 드 풀,스 레 드 이름 은 DubboClient Handler 입 니 다.
사용 하 는 URL 을 다시 만 드 는 것 은 아래 방법 으로 설정 되 지 않 았 기 때문에 기본 형식 이 fixed 인 스 레 드 풀 을 만 들 것 입 니 다.스 레 드 수 는 기본 200 이 고 스 레 드 이름 은 Dubbo 입 니 다.

private void initExecutor(URL url) {
    url = ExecutorUtil.setThreadName(url, CLIENT_THREAD_POOL_NAME);
    url = url.addParameterIfAbsent(THREADPOOL_KEY, DEFAULT_CLIENT_THREADPOOL);
    executor = executorRepository.createExecutorIfAbsent(url);
  }
총결산
그러면 Dubbo-thread 스 레 드 탱크 의 생 성 은 서비스 소비자 와 공급 자 간 의 연결 이 끊 겨 서 만 든 스 레 드 탱크 임 을 알 수 있 습 니 다.프로그램 이 초기 화 될 때 만 든 Dubbo Client Handler 스 레 드 탱크 를 대체 합 니 다.주로 channel 차단 후속 처 리 를 하고 서버 메 시 지 를 받 은 후의 반 직렬 화 등 작업 도 합 니 다.구체 적 인 것 은 ThreadlessExecutor(동기 호출 처리 류),Channel EventRunnable(channel 의 서로 다른 상태 처리,연결,메시지 수신,링크 차단 등 을 볼 수 있 습 니 다.
또 하 나 는 consumer.threadpool 형식,therads 등 정 보 를 설정 하지 않 으 면 연결 을 끊 고 만 든 스 레 드 풀 은 fixed 형식의 스 레 드 풀 이 고 스 레 드 수 는 기본 200 입 니 다.
이 프로그램 에 왜 갑자기 200 개의 Dubbo-thread 스 레 드 가 더 생 겼 는 지 에 대한 설명 은 바로 편집장 이 여러분 에 게 공유 한 모든 내용 입 니 다.참고 가 되 었 으 면 좋 겠 습 니 다.여러분 들 도 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기