Spring

Spring Boot 비동기 처리(@Async)로 성능 향상 원리와 동기/비동기

code2772 2025. 2. 19. 07:36
728x90
반응형

 

1. 코드 작동 방식

 

이 코드는 이미지 다운로드 및 변환 작업을 비동기적으로 실행하는 역할을 합니다.

 

실행 흐름

1. 클라이언트가 processImage(imageUrl)을 호출

2. @Async가 적용된 메서드이므로 새로운 스레드에서 실행

3.  메서드 실행 후 즉시 CompletableFuture 객체를 반환 (메인 스레드 블로킹 없음)

4.  백그라운드에서 downloadAndProcessImage(imageUrl) 실행

5.  작업 완료 후 processedImageUrl을 반환


2. 비동기 성능 향상 원리 (동기 vs. 비동기)

구분 동기 처리 (Synchronous) 비동기 처리 (Asynchronous)

실행 방식 하나의 작업이 끝날 때까지 대기 여러 작업을 동시에 실행
스레드 단일 스레드에서 순차 실행 별도의 스레드에서 비동기 실행
응답 시간 작업이 끝날 때까지 응답 X 작업과 관계없이 즉시 응답 가능
CPU 활용 특정 작업이 끝날 때까지 대기 상태 작업이 끝날 때까지 다른 작업 수행 가능

 

동기 방식 (Before)

public String processImageSync(String imageUrl) {
    // 다운로드 및 변환 작업이 끝날 때까지 대기
    return downloadAndProcessImage(imageUrl);
}

이 방식은 작업이 끝날 때까지 메인 스레드가 대기해야 하므로

대량의 요청이 들어오면 서버가 응답을 늦게 하거나 블로킹(Blocked) 상태가 될 수 있음.


비동기 방식 (After)

@Async
public CompletableFuture<String> processImage(String imageUrl) {
    String processedImageUrl = downloadAndProcessImage(imageUrl);
    return CompletableFuture.completedFuture(processedImageUrl);
}

@Async를 사용하면, 작업을 백그라운드에서 실행하고 즉시 응답을 반환할 수 있음!


3. 실전 예제 – API 응답 속도 비교

동기 방식 (비효율적)

@RestController
@RequestMapping("/sync")
public class SyncController {

    @GetMapping("/process")
    public String processImage(@RequestParam String imageUrl) {
        return imageProcessingService.processImageSync(imageUrl);
    }
}

이 방식의 문제점:

  • 사용자가 요청을 보내면 이미지 처리가 끝날 때까지 기다려야 함.
  • 이미지 처리 시간이 길어질수록 API 응답 속도가 느려짐.

 


비동기 방식 (성능 향상)

@RestController
@RequestMapping("/async")
public class AsyncController {

    @GetMapping("/process")
    public CompletableFuture<String> processImage(@RequestParam String imageUrl) {
        return imageProcessingService.processImage(imageUrl);
    }
}

이 방식의 장점:

  • 클라이언트는 요청을 보내자마자 즉시 응답을 받을 수 있음.
  • 서버는 다른 작업을 동시에 처리할 수 있어 전체적인 성능 향상.

 


4. 실제 성능 차이 (예제 시나리오)

요청 100개를 보냈을 때 (이미지 처리 2초 소요 가정)

방식 응답 속도 (최초 요청) 100개 요청 처리 시간

동기 처리 2초 200초 (2초 × 100개)
비동기 처리 즉시 응답 2초~3초 (동시에 실행)

비동기 방식이 서버에서 동시에 여러 요청을 처리할 수 있기 때문에 훨씬 빠름!


 

5. 추가 최적화 – 비동기 스레드 풀(ThreadPool) 적용

Spring Boot에서는 기본적으로 SimpleAsyncTaskExecutor를 사용하여 새 스레드를 생성하지만,

대량의 요청을 처리할 때는 ThreadPool을 설정하여 최적화하는 것이 좋음.

 

비동기 설정 추가 (스레드 풀 적용)

java
복사편집
@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean(name = "asyncExecutor")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);  // 기본 스레드 개수
        executor.setMaxPoolSize(50);   // 최대 스레드 개수
        executor.setQueueCapacity(100); // 큐 용량
        executor.setThreadNamePrefix("AsyncThread-");
        executor.initialize();
        return executor;
    }
}

 

스레드 풀 적용 후 비동기 메서드

java
복사편집
@Service
public class ImageProcessingService {

    @Async("asyncExecutor")
    public CompletableFuture<String> processImage(String imageUrl) {
        String processedImageUrl = downloadAndProcessImage(imageUrl);
        return CompletableFuture.completedFuture(processedImageUrl);
    }
}

ThreadPool을 적용하면?

  • 비동기 작업이 동시에 처리될 때 불필요한 스레드 생성을 줄이고, 성능을 최적화할 수 있음.
  • CorePoolSize=10 → 최대 10개의 요청을 동시 처리 가능, 이후 요청은 대기열(Queue)에 저장됨.

 

결론 – 비동기 처리의 장점 정리

 

- @Async를 사용하면 메인 스레드가 차단되지 않고 즉시 응답할 수 있음.

- 대량의 요청이 들어와도 처리 성능이 향상되어 서버 다운 위험이 줄어듦.

- ThreadPool을 함께 설정하면 효율적인 리소스 관리가 가능함.

- 비동기 API를 적용하면 API 응답 속도가 빨라지고, 대량의 요청을 동시에 처리할 수 있어 서버 성능이 극대화됩니다! 

 

 

 

 

 

반응형