포스트와 다른 의견은 언제나 환영입니다 👍
예전에 프로젝트에서 "신고하기" API의 속도 개선을 시도한적이 있습니다. API 로직을 살펴보니 "신고한 데이터를 DB에 저장하는 기능" , "신고 내용을 관리자 메일로 전송하는 기능"으로 구성되어 있었습니다. 이때 메일 전송기능은 자바 메일 라이브러리를 사용했는데 해당 라이브러리의 실행시간이 "신고하기" API를 느리게 만든 주범이었습니다!!!
그래서 메일 전송 라이브러리를 다른 유틸 컴포넌트로 분리하고 비동기 방식으로 구성하려 했습니다. 이제부터는 그 당시에 비동기 방식 구현을 위해 공부했던 Async
기능 및 Spring 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
queueCapacity
maxPoolSize
rejectedExecutionHandler
태스크 처리량이 스레드 갯수가 max로 채워지고 queue 대기수를 넘어서는 경우에 RejectExecutionException
이 발생합니다.
다음은 해당 Exception을 다양한 방식으로 처리할수있도록 제공하는 Handler 클래스의 종류입니다.
그렇다면 태스트의 양이 많을 경우 처리순서는 어떻게 될까요?
우선 core 사이즈만큼의 스레드가 일을 처리합니다. 기본 스레드가 처리할 수 있는 작업량을 넘어서는 경우 setQueueCapacity
에서 설정한 크기의 LinkedBlockingQueue를 생성하여 대기합니다 (queueCapacity를 따로 설정하지 않는 경우 Default 크기 만큼 생성). queue도 꽉찬다면 setMaxPoolSize
에서 설정한 만큼 스레드를 추가 생성합니다.
위의 설정대로라면 기본 5개 스레드에서 처리하다가 작업량을 넘어서는 경우 크기가 20인 queue에서 대기하고 큐 크기보다도 초과한다면 최대 10개까지 스레드를 생성합니다.
기존 스레드 갯수 값 까지 스레드 할당(corePoolSize) → 큐 크기 만큼 태스크 큐에서 대기(queueCapacity) → 최대 스레드 갯수 만큼 스레드 추가(maxPoolSize)
이다Async를 사용하기 전에 필요한 ThreadPoolTaskExecutor 설정에 대해 알아보았습니다. Async에 대해서는 2탄에서 다뤄볼게요 👋
reference