[Spring] 쓰레드 풀 설정하기 - ThreadPoolTaskExecutor

gomzu·2023년 2월 14일
2

Spring 시리즈

목록 보기
2/3

포스트와 다른 의견은 언제나 환영입니다 👍

Overview

예전에 프로젝트에서 "신고하기" API의 속도 개선을 시도한적이 있습니다. API 로직을 살펴보니 "신고한 데이터를 DB에 저장하는 기능" , "신고 내용을 관리자 메일로 전송하는 기능"으로 구성되어 있었습니다. 이때 메일 전송기능은 자바 메일 라이브러리를 사용했는데 해당 라이브러리의 실행시간이 "신고하기" API를 느리게 만든 주범이었습니다!!!
그래서 메일 전송 라이브러리를 다른 유틸 컴포넌트로 분리하고 비동기 방식으로 구성하려 했습니다. 이제부터는 그 당시에 비동기 방식 구현을 위해 공부했던 Async 기능 및 Spring Thread Pool에 대해 정리 해보겠습니다.



Thread Pool 설정

쓰레드 풀의 사용을 위해 우선 ThreadPoolTaskExecutor 를 설정해주어야 합니다.
스프링에서 멀티쓰레딩을 편하게 구현 하도록 도와주는 쓰레드 풀 관련 클래스 입니다. org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor 패키지 안에 있습니다.

ThreadPoolTaskExecutor 상위를 보면 java.util.concurrent.Executor 를 구현해 놓았습니다.

설정

    @Bean(name = "taskExecutor")
    public ThreadPoolTaskExecutor executor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setQueueCapacity(20);
        executor.setMaxPoolSize(10);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

corePoolSize

  • 생성해서 사용할 스레드 풀에 속한 기본 스레드 갯수
  • default 값은 1

queueCapacity

  • 이벤트 대기 큐 크기
  • default 값은 Integer.MAX_VALUE (약 21억)

maxPoolSize

  • 최대 스레드 갯수
  • default는 Integer.MAX_VALUE (약 21억)

rejectedExecutionHandler

태스크 처리량이 스레드 갯수가 max로 채워지고 queue 대기수를 넘어서는 경우에 RejectExecutionException 이 발생합니다.
다음은 해당 Exception을 다양한 방식으로 처리할수있도록 제공하는 Handler 클래스의 종류입니다.

  • AbortPolicy
    • default
    • RejectExecutionHandler 예외 발생 시킴
  • DiscardOldestPolicy
    • 오래된 작업을 skip
    • 모든 태스크가 반드시 처리될 필요가 없을때 사용
  • DiscardPolicy
    • 처리하려는 작업을 skip
    • 모든 태스크가 반드시 처리될 필요가 없을때 사용
  • CallerRunsPolicy
    • shutdown 상태가 아니라면 요청한 Caller Thread에서 직접 처리함
    • 태스크 유실을 최소화하기 위해선 이 구현체를 사용해야함

처리 순서

그렇다면 태스트의 양이 많을 경우 처리순서는 어떻게 될까요?

우선 core 사이즈만큼의 스레드가 일을 처리합니다. 기본 스레드가 처리할 수 있는 작업량을 넘어서는 경우 setQueueCapacity 에서 설정한 크기의 LinkedBlockingQueue를 생성하여 대기합니다 (queueCapacity를 따로 설정하지 않는 경우 Default 크기 만큼 생성). queue도 꽉찬다면 setMaxPoolSize 에서 설정한 만큼 스레드를 추가 생성합니다.

위의 설정대로라면 기본 5개 스레드에서 처리하다가 작업량을 넘어서는 경우 크기가 20인 queue에서 대기하고 큐 크기보다도 초과한다면 최대 10개까지 스레드를 생성합니다.



마치며

  • ThreadPoolTaskExecutor 를 잘 설정해서 사용하자
  • 설정 순서는 기존 스레드 갯수 값 까지 스레드 할당(corePoolSize) → 큐 크기 만큼 태스크 큐에서 대기(queueCapacity) → 최대 스레드 갯수 만큼 스레드 추가(maxPoolSize) 이다
  • 스레드 초과로 발생하는 Exception을 처리하는 Handler 클래스가 있다

Async를 사용하기 전에 필요한 ThreadPoolTaskExecutor 설정에 대해 알아보았습니다. Async에 대해서는 2탄에서 다뤄볼게요 👋

reference

profile
Log Of The Day

0개의 댓글