상세 컨텐츠

본문 제목

Spring 비동기 호출과 논블로킹 I/O 적용

출장 자동화 시스템

by myeongjaechoi 2025. 8. 28. 12:45

본문

문제 발견

  1. 항공/숙박 Agent 동시 호출 불가능
  2. @Async 사용시 같은 클래스 내에서 메서드 호출 시 @Async 안 됨
    1. @Async 가 붙은 메서드는 스프링이 프록시 객체로 감싸서 관리
    2. 호출이 프록시를 거칠 때만 별도의 스레드풀에서 실행되어 비동기 처리
    3. 동일 클래스 내에서 자신의 메서드를 직접 호출하면 프록시를 우회함!! -> 비동기 기능 동작X

@Async와 WebClient의 비동기 처리 역할

  • @Async: Spring이 별도 스레드 풀에서 메서드를 실행하도록 해, 서비스 레벨에서 병렬 처리를 가능하게 한다. 여러 요청이나 작업을 동시에 처리할 때 유용하다.
  • WebClient: HTTP 호출 시 네트워크 I/O를 논블로킹(Non-blocking) 방식으로 처리하여 스레드가 그 대기 시간 동안 블로킹되지 않는다. 대규모 네트워크 호출에 효율적이다.
  • 두 기술은 역할이 달라 함께 쓰면 CPU와 네트워크 자원을 모두 효율적으로 쓸 수 있다.

비동기와 병렬 처리 시 고려사항

  • 트랜잭션 관리: 비동기 작업은 별도 스레드에서 실행되므로 기존 트랜잭션 범위와 맞지 않을 수 있다. 비동기 작업 별도 트랜잭션 설계가 필요하다.
  • 상태 동기화: 여러 스레드가 동시에 동일 자원(메모리, DB 등)에 접근하면 경쟁 조건이 발생하니 락이나 안전한 자료구조 사용이 필수.
  • 예외 처리: 비동기 실행 예외는 호출자에 바로 전달되지 않아 별도 로깅, 알림, 재시도 등의 처리가 필요하다.

동기 HTTP 호출과 비동기 HTTP 호출 차이

  • 전통적 RestTemplate은 동기 방식으로, 호출 시 스레드가 응답 대기 중 블로킹된다.
  • 반면 WebClient는 논블로킹 방식으로 네트워크 요청 중에도 스레드를 점유하지 않아 더 효율적이고 많은 동시 요청 처리 가능하다.

비동기 호출만 써도 블로킹 스레드를 쓸 수 있나?

  • @Async는 별도 스레드에서 메서드를 실행하지만, 내부에 동기 호출이 있으면 그 스레드는 그 작업 완료까지 블로킹된다.
  • 동시 요청이 많아지면 스레드 자원 부족이 생길 수 있어 WebClient같은 논블로킹 I/O 도구를 쓰는 것이 추천된다.

실제 적용 사례

  • 서비스 레벨 메서드에 @Async 붙여 병렬로 실행하고,
  • 내부 HTTP 호출은 WebClient로 논블로킹 처리하여 네트워크 지연과 CPU 자원 사용을 모두 최적화한다.

 

추가

MCP에 쓰인 OkHttpClient 도 동기였다. MCP에 전송되는 동안에도 다른 작업들을 할 수 있게 비동기인 WebClient로 변경하였다.

관련글 더보기