본문 바로가기

Spring Boot/비동기 처리

비동기 처리 : 비동기 처리를 왜 해야하는가

동기가 있으면 비동기도 있기 마련

 

 - 대용량 트래픽 환경에서 성능 개선 원리

 - 사용자 경험(UX) 향상을 위한 응답시간 최적화

 - 동기(Synchronous), 비동기(Asynchronous) 처리의 차이

 - Java 비동기 처리와 Spring 비동기 처리의 차이

 - Spring @Async 기능에 대한 기초 개념, @EnableAsync 및 ThreadPool에 대해

 


Spring 비동기 처리를 왜 해야하는가?

오늘날 서비스는 수천 ~ 수만건의 요청을 '동시에' 처리해야함

쇼핑몰, SNS, 게임 서버, 예약 시스템 등에서 요청량 증폭과 응답 속도 저하가 빈번하게 발생함

이럴 때 Spring을 통한 비동기 처리 기능은 성능 개선과 사용자 경험 향상을 동시에 제공하는 핵심 기술이다.

 

1. 대용량 트래픽 환경에서 성능 개선

일반적으로 사용자의 요청은 '요청 - > 처리 - > 응답'의 흐름으로 진행된다

만약 한 요청이 DB조회, 외부 API 호출 등으로 인해 수초가 걸린다면, 해당 스레드는 그 수초동안 아무일도 하지 않고 대기한다.

이걸 스레드 낭비라고 부르며, 이러한 스레드 낭비가 대용량 트래픽 환경에서 심각한 성능 저하로 이어질 수 있다.

 

위와 같은 문제를 비동기(Asynchronous) 처리로 해결한다.

요청을 백그라운드 스레드에게 위임하고, 메인 스레드는 즉시 다음 요청을 처리한다.

비동기 처리

 

스레드의 대기 시간이 줄어들고, 서버는 훨씬 많은 요청을 동시에 처리할 수 있다

 

 

2. 사용자 경험(UX) 향상을 위한 응답 시간 최적화

사용자는 빠른 응답을 가장 먼저 체감한다. 생각해보자. 느린 웹사이트 쓰고 싶은가? 아니요?

비동기 처리를 통해 서버는 '응답'과 '처리'를 분리하여 사용자에게 즉시 피드백을 제공해줄 수 있다.

처리하면서 응답을 동시에 해준다면, 우리가 처리하는게 아니지만 '처리됐구나' 라고 사용자가 생각할 수 있다. 좋은것임

  동기 비동기
사용자 관점 대기 시간 발생 즉시 피드백 제공
시스템 관점 스레드가 대기상태 스레드 재활용 가능
결과 전달 방식 결과를 기다린 후 응답해줌 요청 후 별도 프로세스에서 응답처리

 

비동기처리는 빠른 응답 + 백그라운드 처리를 통해 UX와 성능을 동시에 개선해준다.

 

 

3. 예제

 

1) 동기

public class SyncExample {
    public static void main(String[] args) {
        System.out.println("요청 1 시작");
        process();
        System.out.println("요청 1 완료");
    }

    private static void process() {
        try {
            Thread.sleep(2000);
            System.out.println("처리 완료");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

우리가 기존에 돌리던 main 메서드임, 모든 순서가 순차적으로 실행된다

 

2) 비동기

import java.util.concurrent.CompletableFuture;

public class AsyncExample {
    public static void main(String[] args) {
        System.out.println("요청 1 시작");

        CompletableFuture.runAsync(() -> { // CompletableFuture.runAsync()를 통해 비동기처리
            try {
                Thread.sleep(2000);
                System.out.println("비동기 처리 완료");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        System.out.println("요청 1 완료 (즉시 반환)");
    }
}

 

 

 

4. Spring 비동기 처리의 역할

단순 자바 수준의 병렬 실행을 넘어서, 서비스 계층 전체에서 비즈니스 로직 단위로 비동기 실행을 제어할 수 있다고 함

  Java CompletableFuture Spring @Async
스레드 관리 직접 Executor 작성 필요 Spring이 ThreadPoolTaskExecutor로 관리
코드 구조 코드 내부에 Future 체인 필요 메서드에 @Async 추가하면됨
예외처리 try-catch exceptionally() 직접 처리 AsyncUncaughtExceptionHandler 자동 관리
통합성 독립실행 트랜잭션, 보안, AOP 통합가능

 

 

5. 실전에서 대용량 이메일 발송할 때..

시나리오 동기처리시 문제점 비동기 처리효과
1만명의 사용자에게 메일 발송 한명씩 순차발송 - > 응답시간 5분 이상 요청 즉시 응답후 백그라운드 발송
외부 SMTP API 호출지연 API 대기시간 누적 별도 스레드에서 병렬 실행
사용자 응답속도 매우 느림 즉시 "요청 접수됨" 표시

 


 - 데이터 정합성이 중요한 트랜잭션의 경우 반드시 동기 처리해야함

 - 이메일, 알림, 로그, 외부 연동 등은 비동기 처리를 통해 효율을 극대화할 수 있음

 - 비동기 예외는 메인 스레드로 전파되지 않기 때문에 AsyncUncaughtExceptionHandler를 설정해야함

 - 스레드풀의 크기와 큐 용량을 환경에 맞게 조정해야함

 - @Async를 사용하려면 반드시 @EnableAsync 설정이 필요함

 


정리

항목 요약
비동기 처리의 목적 대용량 트래픽에서 성능을 높이고, 응답속도를 개선함
UX 향상 포인트 사용자가 기다리지 않도록 즉시 피드백 제공
Spring의 역할 비즈니스 단위에서 간단하게 비동기 실행을 제어
Java와의 차이 코드 단순화 + 스레드 관리 자동화