-
[Spring, Spring Boot] 비동기 처리 TaskExecutorSpring 2024. 11. 28. 14:39
Spring Boot에서 TaskExecutor를 활용해 비동기 처리의 스레드 풀을 직접 커스터마이징 할 수 있습니다. 기본적으로 Spring은 SimpleAsyncTaskExecutor라는 기본 스레드 풀을 사용하지만, 애플리케이션의 성능을 최적화하거나 특정 요구사항을 충족하기 위해 스레드 풀 설정을 직접 수정하는 경우가 많습니다. 아래는 TaskExecutor를 작성하여 스레드 풀을 커스터마이징하는 방법입니다.
TaskExecutor 작성하기
Spring Boot에서 TaskExecutor를 설정하려면 ThreadPoolTaskExecutor를 빈으로 등록해야 합니다. 이를 통해 스레드 풀의 동작 방식을 유연하게 제어할 수 있습니다.
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @Configuration @EnableAsync public class AsyncConfig implements AsyncConfigurer { @Bean(name = "taskExecutor") public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); // 기본적으로 유지할 최소 스레드 수 executor.setMaxPoolSize(10); // 최대 생성 가능한 스레드 수 executor.setQueueCapacity(25); // 큐에 들어갈 수 있는 작업 수 executor.setThreadNamePrefix("Async-Thread-"); // 스레드 이름의 접두사 설정 executor.initialize(); return executor; } } // 위 설정에서는 ThreadPoolTaskExecutor를 이용하여 스레드 풀을 커스터마이징하였습니다.
- CorePoolSize: 기본적으로 유지할 스레드 수입니다. 비동기 요청이 들어오면 이 스레드들이 먼저 사용됩니다.
- MaxPoolSize: 최대 생성 가능한 스레드 수입니다. 만약 core pool의 스레드가 모두 사용 중일 때 추가적인 스레드가 생성될 수 있습니다.
- QueueCapacity: 큐에 저장할 수 있는 작업의 수입니다. 만약 스레드가 모두 사용 중일 경우 작업은 이 큐에 쌓이게 됩니다.
- ThreadNamePrefix: 생성되는 스레드의 이름 접두사로, 디버깅 시 어떤 스레드가 비동기 작업을 처리하고 있는지 쉽게 알 수 있습니다.
2. @Async 어노테이션에서 TaskExecutor 사용하기
@Async 어노테이션을 사용하여 비동기 작업을 수행할 때, 특정 스레드 풀을 사용하도록 설정할 수 있습니다. 예를 들어, 위에서 정의한 taskExecutor를 사용하여 EmailService를 개선해 보겠습니다.
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.stereotype.Service; @Service public class EmailService { @Async("taskExecutor") public void sendEmail(String email) { System.out.println("이메일 발송 시작 (스레드: " + Thread.currentThread().getName() + "): " + email); try { Thread.sleep(5000); // 이메일 발송에 5초 걸린다고 가정 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("이메일 발송 완료 (스레드: " + Thread.currentThread().getName() + "): " + email); } } // 위 코드에서는 **@Async("taskExecutor")**로 특정 TaskExecutor를 지정하고 있습니다. // 이렇게 하면 sendEmail() 메서드는 AsyncConfig에서 설정한 스레드 풀에서 실행됩니다.
코드 실행 결과
- 이메일 발송 요청을 여러 번 호출하면 아래와 같은 콘솔 로그를 확인할 수 있습니다.
이메일 발송 시작 (스레드: Async-Thread-1): test1@example.com 이메일 발송 시작 (스레드: Async-Thread-2): test2@example.com 이메일 발송 시작 (스레드: Async-Thread-3): test3@example.com 이메일 발송 완료 (스레드: Async-Thread-1): test1@example.com 이메일 발송 완료 (스레드: Async-Thread-2): test2@example.com // 각 이메일 발송 작업이 // 별도의 스레드(Async-Thread-1, Async-Thread-2, ...)에서 동시에 실행되고 있음을 볼 수 있습니다.
결론
Spring Boot에서 ThreadPoolTaskExecutor를 통해 스레드 풀을 커스터마이징하여 비동기 작업의 성능을 최적화할 수 있습니다. 이러한 설정은 트래픽이 많은 서비스나 병렬로 처리해야 하는 작업에서 시스템의 성능을 높이는 데 매우 유용합니다. 스레드 풀의 크기를 적절히 설정하면 리소스 사용량을 효율적으로 관리하고, 비동기 작업의 처리를 안정적으로 수행할 수 있습니다.
'Spring' 카테고리의 다른 글
[Spring, Spring Boot] 데이터 캐싱(Caching) (0) 2024.12.11 [Spring Boot] RESTful API 설계 원칙 (0) 2024.12.02 [Spring, Spring Boot] 비동기 처리 Asynchronous Processing (0) 2024.11.28 [Spring, Spring Boot] 관점 지향 프로그래밍 AOP (Aspect-Oriented Programming) (0) 2024.11.28 [Spring, Spring Boot] 의존성 주입 (Dependency Injection, DI) (0) 2024.11.28