WebClient 기반 비동기 처리 최적화
외부 API 호출은 많은 서비스에서 가장 큰 지연 요인이다.
동기 RestTemplate은 요청마다 스레드를 점유하기 때문에, 트래픽이 증가하면 스레드 고갈(thread exhaustion) 문제가 발생한다.
Spring WebClient는 비동기·논블로킹 방식으로 외부 API를 처리하여 더 높은 동시성과 효율을 제공한다.
이 글에서는 WebClient의 핵심 개념과 성능 최적화 전략을 정리한다.
#RestTemplate과 WebClient 비교
RestTemplate은 동기 방식으로, 요청마다 스레드가 점유된다.
반면 WebClient는 이벤트 기반 비동기 구조로, 요청 대기 시간 동안 스레드를 반환하므로 높은 동시성을 처리할 수 있다.
RestTemplate 한계
- 요청 동안 스레드 점유 → 동시 요청 수 제한
- 느린 외부 API가 전체 서비스 속도를 늦춤
- 멀티 IO 작업에 비효율적
WebClient 장점
- 논블로킹 IO 기반
- 스레드 점유 없음 → 높은 동시성
- 멀티 외부 API 호출에 최적
- Stream 처리 및 SSE(Server Sent Event)까지 지원
Virtual Thread와 WebClient를 비교하면, WebClient는 “지연 시간이 긴 외부 API 병렬 호출”에서 더 강력하다.
#WebClient 기본 구성
Spring Boot 3.x에서는 WebClient를 기본 HTTP 클라이언트로 권장한다.
커넥션 재사용, 타임아웃, 풀 설정이 성능에 큰 영향을 준다.
WebClient Bean 등록
@Bean
public WebClient webClient() {
return WebClient.builder()
.baseUrl("https://api.example.com")
.build();
}
간단한 GET 요청
Mono<UserResponse> user = webClient.get()
.uri("/user/{id}", id)
.retrieve()
.bodyToMono(UserResponse.class);
Mono는 단일 결과, Flux는 여러 개의 스트림 결과를 의미한다.
#성능 최적화 설정
WebClient 성능은 HTTP 커넥션 풀 설정과 타임아웃 설정에 크게 영향을 받는다.
적절한 커넥션 수는 시스템의 동시 API 호출량에 따라 달라진다.
1) 커넥션 풀 크기 조절
HttpClient httpClient = HttpClient.create()
.secure()
.compress(true)
.keepAlive(true)
.responseTimeout(Duration.ofSeconds(3))
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 2000);
WebClient client = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
2) 타임아웃 설정
외부 API가 느릴 경우 서비스 전체가 느려지는 것을 방지한다.
.responseTimeout(Duration.ofSeconds(2))
3) Keep-Alive 활성화
매 요청마다 TCP 커넥션을 새로 생성하면 비용이 크다.
Keep-Alive를 통해 커넥션을 재사용하면 속도가 크게 개선된다.
#멀티 외부 API 호출 최적화
WebClient는 IO 대기 중 스레드를 붙잡지 않기 때문에,
여러 외부 API를 병렬 호출할 때 성능 차이가 극적으로 나타난다.
병렬 호출 예시
Mono<A> a = webClient.get().uri("/a").retrieve().bodyToMono(A.class);
Mono<B> b = webClient.get().uri("/b").retrieve().bodyToMono(B.class);
Mono<Result> result = Mono.zip(a, b)
.map(tuple -> new Result(tuple.getT1(), tuple.getT2()));
RestTemplate에서는 2개의 API를 직렬로 호출해 2배 시간이 걸리지만,
WebClient는 병렬 처리로 대기 시간을 크게 줄일 수 있다.
#Resilience4j와의 조합
WebClient는 비동기이기 때문에 Circuit Breaker와 Rate Limit 전략과 함께 사용할 때 효과가 크다.
Circuit Breaker 적용
Mono<User> response = webClient.get()
.uri("/user")
.retrieve()
.bodyToMono(User.class)
.transformDeferred(CircuitBreakerOperator.of(circuitBreaker));
Retry 적용
.retryWhen(Retry.backoff(3, Duration.ofMillis(200)))
외부 API가 불안정해도 WebClient + Resilience4j 조합이면 안정적인 서비스를 유지할 수 있다.
#Virtual Thread와 WebClient 비교
Java 21 Virtual Thread와 WebClient는 모두 동시성 처리 능력이 뛰어나지만, 사용 목적이 다르다.
Virtual Thread가 적합한 상황
- DB 중심의 내부 API
- 외부 API 호출이 적은 서비스
- 기존 동기 코드 유지하고 싶을 때
WebClient가 적합한 상황
- 외부 API 호출이 매우 많을 때
- API 병렬 호출이 필요한 서비스
- IO 대기 시간이 긴 API
- SSE 또는 스트리밍이 필요한 케이스
즉, WebClient는 외부 IO 중심 서비스에서 가장 강력하다.
마치며
WebClient는 Spring Boot에서 외부 API 성능을 획기적으로 개선할 수 있는 핵심 기술이다.
스레드를 점유하지 않는 비동기 구조 덕분에 대규모 트래픽 환경에서도 안정적이고 빠른 응답을 제공한다.
다음 글에서는 API 보안 및 인증 구조 성능 최적화 (JWT, 세션, OAuth2)를 다룬다.
보안과 성능을 동시에 충족시키는 실전 전략을 정리해볼 예정이다.
'TIL' 카테고리의 다른 글
| Spring Boot 성능 최적화 10 (0) | 2025.11.12 |
|---|---|
| Spring Boot 성능 최적화 9 (0) | 2025.11.11 |
| 11/7 (0) | 2025.11.07 |
| 11/6 (0) | 2025.11.06 |
| 11/5 (0) | 2025.11.05 |