tomcat 스 레 드 탱크 정책

10206 단어 tomcat
순서.
tomcat 의 스 레 드 탱크 는 jdk 의 executor 를 확장 하 였 으 며, 대기 열 은 자신의 task quue 를 사용 하 였 으 므 로, 그 전략 은 jdk 와 다 르 므 로 주의해 야 합 니 다. 그렇지 않 으 면 구 덩이 를 밟 기 쉽 습 니 다.
tomcat 스 레 드 탱크 정책
  • 장면 1: 요청 을 받 아들 입 니 다. 이때 tomcat 가 시작 하 는 스 레 드 수가 core PoolSize tomcat minSpareThreads 에 이 르 지 않 았 습 니 다. tomcat 는 스 레 드 를 시작 하여 이 요청 을 처리 합 니 다.
  • 장면 2: 요청 을 받 아들 입 니 다. 이때 tomcat 가 시작 한 스 레 드 수 는 core PoolSize 에 도 달 했 습 니 다. tomcat 는 이 요청 을 대기 열 offer 에 넣 었 습 니 다. 대기 열 에 넣 으 면 되 돌아 갑 니 다. 대기 열 에 넣 지 못 하면 작업 스 레 드 를 추가 하려 고 합 니 다. 현재 스 레 드 개수
  • 주의해 야 할 것 은 링크 드 BlockingQueue 를 사용 하면 기본적으로 Integer. MAX 를 사용 합 니 다.VALUE, 즉 무 계 대기 열 (이 경우 대기 열 을 설정 한 capacity 가 없 으 면 대기 열 이 채 워 지지 않 습 니 다. 그러면 새 스 레 드 를 열 어 max Threads 개수 에 도달 할 수 없 을 때 max Threads 를 설정 하 는 것 은 무의미 합 니 다).
    그리고 TaskQueue 의 대기 열 capacity 는 max Queue Size 이 고 기본 값 도 Integer. MAX 입 니 다.VALUE。그러나, offer 를 다시 쓰 는 방법 은 스 레 드 탱크 크기 가 maximumPoolSize 보다 작 을 때 false 로 돌아 갑 니 다. 즉, 대기 열 이 가득 찬 논 리 를 어느 정도 바 꾸 었 고, LinkedBlockingQueue 를 사용 하 는 기본 capacity 는 Integer. MAX 입 니 다.VALUE 때 max Threads 가 실 효 된 'bug' 입 니 다.따라서 max Threads 까지 스 레 드 를 계속 늘 리 고 초과 한 후에 대기 열 에 계속 넣 을 수 있 습 니 다.
    TaskQueue 의 offer 동작
    @Override
        public boolean offer(Runnable o) {
          //we can't do any checks
            if (parent==null) return super.offer(o);
            //we are maxed out on threads, simply queue the object
            if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
            //we have idle threads, just add it to the queue
            if (parent.getSubmittedCount()

    StandardThreadExecutor
    /**
         * Start the component and implement the requirements
         * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
         *
         * @exception LifecycleException if this component detects a fatal error
         *  that prevents this component from being used
         */
        @Override
        protected void startInternal() throws LifecycleException {
    
            taskqueue = new TaskQueue(maxQueueSize);
            TaskThreadFactory tf = new TaskThreadFactory(namePrefix,daemon,getThreadPriority());
            executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), maxIdleTime, TimeUnit.MILLISECONDS,taskqueue, tf);
            executor.setThreadRenewalDelay(threadRenewalDelay);
            if (prestartminSpareThreads) {
                executor.prestartAllCoreThreads();
            }
            taskqueue.setParent(executor);
    
            setState(LifecycleState.STARTING);
        }

    주의해 야 할 것 은 tomcat 의 스 레 드 탱크 는 Executors 공장 방법 에 사용 되 는 링크 드 BlockingQueue 가 아 닌 확장 taskQueue 를 사용 합 니 다.( offer )
    여기 max QueueSize 기본 값 은
    /**
         * The maximum number of elements that can queue up before we reject them
         */
        protected int maxQueueSize = Integer.MAX_VALUE;

    org/apache/tomcat/util/threads/ThreadPoolExecutor
    /**
         * Executes the given command at some time in the future.  The command
         * may execute in a new thread, in a pooled thread, or in the calling
         * thread, at the discretion of the Executor implementation.
         * If no threads are available, it will be added to the work queue.
         * If the work queue is full, the system will wait for the specified
         * time and it throw a RejectedExecutionException if the queue is still
         * full after that.
         *
         * @param command the runnable task
         * @param timeout A timeout for the completion of the task
         * @param unit The timeout time unit
         * @throws RejectedExecutionException if this task cannot be
         * accepted for execution - the queue is full
         * @throws NullPointerException if command or unit is null
         */
        public void execute(Runnable command, long timeout, TimeUnit unit) {
            submittedCount.incrementAndGet();
            try {
                super.execute(command);
            } catch (RejectedExecutionException rx) {
                if (super.getQueue() instanceof TaskQueue) {
                    final TaskQueue queue = (TaskQueue)super.getQueue();
                    try {
                        if (!queue.force(command, timeout, unit)) {
                            submittedCount.decrementAndGet();
                            throw new RejectedExecutionException("Queue capacity is full.");
                        }
                    } catch (InterruptedException x) {
                        submittedCount.decrementAndGet();
                        throw new RejectedExecutionException(x);
                    }
                } else {
                    submittedCount.decrementAndGet();
                    throw rx;
                }
    
            }
        }

    jd k 라인 풀 의 기본 Rejected 규칙, 즉 catch 가 Rejected Execution Exception 을 바 꾸 었 습 니 다.정상 jdk 의 규칙 은 core 스 레 드 수 + 임시 스 레 드 수 > max Size 일 때 Rejected Execution Exception 을 던 집 니 다.여기 catch 가 있 으 면 taskQueue 에 계속 넣 으 세 요.
    public boolean force(Runnable o, long timeout, TimeUnit unit) throws InterruptedException {
            if ( parent==null || parent.isShutdown() ) throw new RejectedExecutionException("Executor not running, can't force a command into the queue");
            return super.offer(o,timeout,unit); //forces the item onto the queue, to be used if the task is rejected
        }

    여기 서 호출 된 슈퍼. offer (o, timeout, unt), 즉 링크 드 BlockingQueue 입 니 다. 열 이 가득 찼 을 때 false 로 돌아 가 야 Rejected Execution Exception 을 다시 던 집 니 다.( jdk ThreadPoolExecutor RejectedExecutionException , maxThreads RejectedExecutionException, , taskQueue , RejectedExecutionException )
    JD K 라인 풀 정책
  • 작업 을 제출 할 때마다 스 레 드 수가 core Size 에 도달 하지 않 으 면 새 스 레 드 를 만 들 고 이 작업 을 연결 합 니 다.따라서 첫 번 째 core Size 가 임 무 를 제출 한 후 스 레 드 의 총 수 는 core Size 에 달 해 야 하 며, 이전의 빈 스 레 드 를 다시 사용 하지 않 습 니 다.
  • 스 레 드 수가 core Size 에 이 르 면 새로 추 가 된 임 무 는 작업 대기 열 에 넣 고 스 레 드 탱크 의 스 레 드 는 take () 를 사용 하여 작업 대기 열 에서 일 을 하려 고 노력 합 니 다.
  • 대기 열 이 경계 대기 열 이 고 스 레 드 탱크 의 스 레 드 가 제때에 작업 을 가 져 가지 못 하면 작업 대기 열 이 가득 차 서 작업 을 삽입 하 는 데 실패 할 수 있 습 니 다. 이때 스 레 드 탱크 는 긴급 하 게 새로운 임시 스 레 드 를 만들어 서 보완 할 것 입 니 다.
  • 임시 스 레 드 는 poll (keepAliveTime, timeUnit) 을 사용 하여 작업 대기 열 에서 일 을 끌 어 당 긴 다. 때 가 되 어도 빈손으로 일 을 끌 지 못 하면 너무 한가 하 다 는 뜻 으로 해고 된다.
  • core 스 레 드 수 + 임시 스 레 드 수 > max Size 가 있 으 면 새로운 임시 스 레 드 를 만 들 수 없습니다. 고 개 를 돌려 RejectExecution Hanlder 를 실행 합 니 다.기본 적 인 AbortPolicy 는 Rejected Execution Exception 이상 을 포기 합 니 다. 다른 선택 은 현재 작업 (Discard) 을 조용히 포기 하거나 작업 대기 열 에서 가장 오래된 작업 (DisacardOldest) 을 포기 하거나 메 인 라인 에서 직접 수행 하 는 것 을 포함 합 니 다 (CallerRuns).
  • 소스 코드
    /**
         * Executes the given task sometime in the future.  The task
         * may execute in a new thread or in an existing pooled thread.
         *
         * If the task cannot be submitted for execution, either because this
         * executor has been shutdown or because its capacity has been reached,
         * the task is handled by the current {@code RejectedExecutionHandler}.
         *
         * @param command the task to execute
         * @throws RejectedExecutionException at discretion of
         *         {@code RejectedExecutionHandler}, if the task
         *         cannot be accepted for execution
         * @throws NullPointerException if {@code command} is null
         */
        public void execute(Runnable command) {
            if (command == null)
                throw new NullPointerException();
            /*
             * Proceed in 3 steps:
             *
             * 1. If fewer than corePoolSize threads are running, try to
             * start a new thread with the given command as its first
             * task.  The call to addWorker atomically checks runState and
             * workerCount, and so prevents false alarms that would add
             * threads when it shouldn't, by returning false.
             *
             * 2. If a task can be successfully queued, then we still need
             * to double-check whether we should have added a thread
             * (because existing ones died since last checking) or that
             * the pool shut down since entry into this method. So we
             * recheck state and if necessary roll back the enqueuing if
             * stopped, or start a new thread if there are none.
             *
             * 3. If we cannot queue task, then we try to add a new
             * thread.  If it fails, we know we are shut down or saturated
             * and so reject the task.
             */
            int c = ctl.get();
            if (workerCountOf(c) < corePoolSize) {
                if (addWorker(command, true))
                    return;
                c = ctl.get();
            }
            if (isRunning(c) && workQueue.offer(command)) {
                int recheck = ctl.get();
                if (! isRunning(recheck) && remove(command))
                    reject(command);
                else if (workerCountOf(recheck) == 0)
                    addWorker(null, false);
            }
            else if (!addWorker(command, false))
                reject(command);
        }

    작은 매듭
    tomcat 의 스 레 드 탱크 와 jdk 의 사용 무 계 링크 드 BlockingQueue 는 주로 다음 과 같은 두 가지 차이 가 있 습 니 다.
  • jdk 의 Thread PoolExecutor 의 스 레 드 풀 성장 전략 은 대기 열 이 경계 대기 열 이 고 스 레 드 풀 의 스 레 드 가 제때에 임 무 를 가 져 가지 못 하면 작업 대기 열 이 가득 차 서 임 무 를 삽입 하 는 데 실패 할 수 있 습 니 다. 이때 스 레 드 풀 은 긴급 하 게 새로운 임시 스 레 드 를 만들어 서 보완 합 니 다.한편, tomcat 의 Thread PoolExecutor 가 사용 하 는 taskQueue 는 무한 한 Linked BlockingQueue 이지 만 taskQueue 의 offer 방법 을 통 해 Linked BlockingQueue 의 offer 방법 을 덮어 쓰 고 규칙 을 바 꾸 어 jdk 의 Thread PoolExecutor 의 경계 대기 열 스 레 드 성장 전략 을 사용 합 니 다.
  • jdk 의 ThreadPoolExecutor 스 레 드 풀 은 core 스 레 드 수 + 임시 스 레 드 수 > max Size 가 있 으 면 새로운 임시 스 레 드 를 만 들 수 없습니다. 고 개 를 돌려 RejectExecution Hanlder 를 실행 합 니 다.한편, tomcat 의 Thread PoolExecutor 는 이 규칙 을 바 꾸 었 습 니 다. 즉, catch 는 RejectExecution Hanlder 를 붙 잡 고 대기 열 에 계속 넣 었 습 니 다. 대기 열 이 다 찼 을 때 까지 RejectExecution Hanlder 를 던 졌 습 니 다.기본 taskQueue 는 무한 합 니 다.

  • 의문: taskQueue 가 무한 한 이상 tomcat 서버 의 수신 요청 제한 을 어디서 제어 하고 스스로 보호 하 는 지.그리고 acceptCount 와 max Connections 는 어떤 관계 입 니까?
    doc
  • Tomcat 성능 최적화
  • Tomcat 튜 닝
  • 대화 병행 (3) - JAVA 스 레 드 탱크 의 분석 과 사용
  • Java ThreadPool 의 올 바른 오픈 방식
  • Tomcat 의 커 넥 터 구성 요소
  • Tomcat hang 주 문제 조사 수기
  • 좋은 웹페이지 즐겨찾기