RestTemplate vs WebClient

Casper·2023년 8월 23일
0
post-thumbnail

RestTemplate?

Spring 3부터 제공되는 전통적인 Blocking HTTP Client입니다.
Apache HttpClient 라이브러리를 활용하여 개발되었으며
HTTP 요청을 생성하기 위해 간단한 API를 제공하며 현재까지도 많은 프로젝트에서 활용되는 HTTP Client입니다.
Java Servlet API를 활용하고 있기 때문에 기본적으로 하나의 스레드당 하나의 요청 방식으로 되어있으며 이는 클라이언트가 응답을 받을 때까지 스레드는 Block 상태이기 때문에 서버 자원과 응답 시간에 영향을 미치는 것을 의미합니다.
또한 많은 요청이 들어오면 이에 비례하여 스레드가 생성되기 때문에 메모리와 스레드풀에 영향을 미치고 잦은 Context Switching으로 인해 효율성이 저하됩니다.

Web Client?

Spring 5부터 제공되는 최신 Non-Blocking Reactive HTTP Client입니다.
Non-Blocking을 지원하기 위해 Spring Reactive Framework를 기반으로 개발되었습니다.
Reactive Framework는 Event-Driven 구조를 사용하기 때문에 비동기 로직을 Reactive Stream API를 통해 제공하게 됩니다.
이는 RestTemplate와 비교하여 적은 양의 스레드와 시스템 자원만으로 많은 요청을 처리할 수 있음을 의미하기 때문 많은 양의 요청을 병렬로 처리해야하는 경우 적합한 HTTP Client입니다.

RestTemplate vs Web Client (Concept)

두 클라이언트간 주요 차이점을 알아보겠습니다.

동기 / 비동기

RestTemplate는 요청에 대한 응답이 수신될 때까지 호출한 스레드를 Blocking하는 동기식 클라이언트입니다.
반면에 WebClient는 Non-Blocking 방식이기 때문에 메인 스레드를 차단하지 않고 여러 요청을 동시에 수행이 가능합니다.

반응형 / 비반응형

RestTemplate은 전통적인 비반응형 클라이언트인 반면,
WebClient는 반응형 프로그래밍을 지원함으로써 대용량 데이터를 보다 효율적으로 처리할 수 있습니다.

오류 처리

RestTemplate는 예외를 발생시켜 오류를 처리하는 방식을 사용하고 있습니다.
반면에 WebClient는 반응형 스트림을 사용하여 오류를 전파하기 때문에 오류를 좀 더 쉽게 처리할 수 있습니다.

직렬화 / 역직렬화

RestTemplate는 다른 외부 라이브러리를 통해 객체를 (역)직렬화 하는 반면에
WebClient는 Spring에 내장된 기능을 사용하여 (역)직렬화하기 때문에 별도의 라이브러리가 필요하지 않습니다.

RestTemplate vs Web Client (Logic with Code)

RestTemplate

@GetMapping("/tweets-blocking")
public List<Tweet> getTweetsBlocking() {
    log.info("Starting BLOCKING Controller!");
    final String uri = getSlowServiceUri();

    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<List<Tweet>> response = restTemplate.exchange(
      uri, HttpMethod.GET, null,
      new ParameterizedTypeReference<List<Tweet>>(){});

    List<Tweet> result = response.getBody();
    result.forEach(tweet -> log.info(tweet.toString()));
    log.info("Exiting BLOCKING Controller!");
    return result;
}

먼저 RestTemplate 예시 코드입니다.
RestTemplate는 동기적인 특성으로 인해 restTemplate.exchange 응답을 받을 때까지 Blocking 상태일 것이며 이 후의 코드는 Blocking 후에야 실행될 것입니다.

Starting BLOCKING Controller!
Tweet(text=RestTemplate rules, username=@user1)
Tweet(text=WebClient is better, username=@user2)
Tweet(text=OK, both are useful, username=@user1)
Exiting BLOCKING Controller!

콘솔에 나타난 실행 흐름입니다.

WebClient

@GetMapping(value = "/tweets-non-blocking", 
            produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Tweet> getTweetsNonBlocking() {
    log.info("Starting NON-BLOCKING Controller!");
    Flux<Tweet> tweetFlux = WebClient.create()
      .get()
      .uri(getSlowServiceUri())
      .retrieve()
      .bodyToFlux(Tweet.class);

    tweetFlux.subscribe(tweet -> log.info(tweet.toString()));
    log.info("Exiting NON-BLOCKING Controller!");
    return tweetFlux;
}

다음은 WebClient 예시 코드입니다.
Web Client가 일련의 데이터 스트림인 Flux 객체를 반환하고 메서드 실행이 완료됩니다.
/tweets-non-blocking endpoint를 호출하는 클라이언트도 반환된 Flux 개체에 가입됩니다.

Starting NON-BLOCKING Controller!
Exiting NON-BLOCKING Controller!
Tweet(text=RestTemplate rules, username=@user1)
Tweet(text=WebClient is better, username=@user2)
Tweet(text=OK, both are useful, username=@user1)

콘솔에 나타난 결과 응답과 상관없지 메서드가 종료된 것을 알 수 있습니다.

Summary

RestTemplate도 현재까지 아직 사용중이지만
위에서 설명드린 특성들로 인해 WebClient가 성능상 이점을 많이 갖고 있기 때문에 HTTP Client를 선택해야할 때 이 점에 대해 인지하고 개발을 하면 좋겠습니다.

profile
Emotional Developer

0개의 댓글