ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring, Spring Boot] 비동기 처리 TaskExecutor
    Spring 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를 통해 스레드 풀을 커스터마이징하여 비동기 작업의 성능을 최적화할 수 있습니다. 이러한 설정은 트래픽이 많은 서비스병렬로 처리해야 하는 작업에서 시스템의 성능을 높이는 데 매우 유용합니다. 스레드 풀의 크기를 적절히 설정하면 리소스 사용량을 효율적으로 관리하고, 비동기 작업의 처리를 안정적으로 수행할 수 있습니다.

    댓글

Designed by Tistory.