1. 문제
수만 명의 유저가 동시에 접속하여 화상 회의를 개설하거나 대량의 푸시 알림을 요청할 때, 서버의 전체 응답 속도가 걷잡을 수 없이 느려지는 병목(Bottleneck) 현상이 발생합니다.
서버의 제한된 스레드들이 외부 API 호출이나 메일 발송같이 오래 걸리는 동기식(Synchronous) 작업을 처리하느라 묶여버리면, 다른 유저들의 가벼운 요청마저 끝없는 대기열(Queue)에 갇히기 때문입니다.
2. 왜 필요한가
결제처럼 순서와 결과가 즉각 필요한 작업이 아니라면, 무겁고 오래 걸리는 작업은 뒷단(Background)으로 던져버리고 유저에게는 즉각적인 응답(Success)을 반환해야 합니다.
이를 통해 어플리케이션의 핵심 스레드 자원 고갈을 막고, 단일 서버가 뻗지 않고 감당할 수 있는 초당 처리량(TPS)을 한계치까지 끌어올려야 합니다.
3. 기대효과
Spring Boot의 비동기 처리(@Async)와 맞춤형 ThreadPool을 도입하면, 병목 구간의 응답 시간이 기존 대비 90% 이상 단축되는 극적인 체감 성능 향상을 보입니다.
타사 API 지연이나 네트워크 장애가 발생하더라도 메인 서비스의 속도에는 전혀 영향을 주지 않는 견고한 내결함성(Fault Tolerance)을 확보할 수 있습니다.
4. 구현 방향
빠른 요청을 처리하는 기본 톰캣(Tomcat) 스레드와, 오래 걸리는 작업을 전담하는 ‘격리된 스레드 풀(Thread Pool)’을 분리하여 @Async 어노테이션으로 작업을 위임합니다.
아래는 메인 스레드의 방해 없이 외부 푸시 알림 같은 무거운 작업을 백그라운드 워커들에게 비동기로 떠넘기는 핵심 구현 로직입니다.
@Configuration
@EnableAsync
public class AsyncConfig {
// 1. 무거운 작업을 전담할 별도의 '비동기 스레드 풀' 생성
@Bean(name = "notificationTaskExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10); // 기본 대기 스레드
executor.setMaxPoolSize(50); // 트래픽 피크 시 최대 확장
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("Async-Noti-");
executor.initialize();
return executor;
}
}
@Service
public class NotificationService {
// 2. 메인 스레드 차단 없이 백그라운드 스레드에서 알림 발송 처리
@Async("notificationTaskExecutor")
public void sendHeavyPushNotification(String userId, String message) {
// (예: 외부 FCM API 호출 등 수 초가 소요되는 I/O 로직)
externalPushApi.send(userId, message);
}
}
5. 비즈니스 가치
답답한 로딩 화면을 없애 고객 이탈률을 최소화함과 동시에, 트래픽 폭주 시에도 더 적은 서버 대수로 막대한 요청을 감당해 내어 막대한 클라우드 인프라 비용을 절감합니다.
결국 백엔드 아키텍처의 철저한 비동기 최적화는 비즈니스의 이익 극대화와 서비스 신뢰도를 동시에 견인하는 가장 강력한 엔진이 됩니다.