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 응답 속도가 빨라지고, 대량의 요청을 동시에 처리할 수 있어 서버 성능이 극대화됩니다!
'Spring' 카테고리의 다른 글
Spring Security 기본(세션, 스프링시큐리티) (0) | 2023.03.13 |
---|---|
Spring 시험 (7번), Thymleaf 이용 리스트 출력 (1) | 2023.01.09 |
Spring Project Board 2 (Repository, DTO, PageController) - 타임리프 SQL 출력 (1) | 2023.01.08 |
Spring Project Board(게시판) 1 (0) | 2023.01.02 |
Spring 유용한 Setting, 사이트 (0) | 2022.12.29 |