프로젝트 진행 중 OpenAI API를 연동하는 과정에서, RestTemplateWebClient 두 가지 방법의 차이점과 각각의 장단점에 대해 고민하게 되었습니다.

 

스프링 애플리케이션에서 HTTP 요청을 처리하는 방법으로 RestTemplateWebClient가 있습니다. 스프링 5.0 이전까지는 RestTemplate이 주로 사용되었으나, 스프링 5.0 이후로는 WebClient가 새로 도입되어 현재는 WebClient를 사용하는 것이 권장되고 있습니다.

 

그럼 RestTemplateWebClient는 각각 어떤 특징을 가지고 있으며, 왜 WebClient를 권장하는지 자세히 살펴보겠습니다.

 

 

RestTemplate

RestTemplate 이란?

스프링 3.0에서부터 지원하는 RestTemplate은 HTTP 통신에 유용하게 쓸 수 있는 템플릿입니다. 자바에서 API 호출을 위해 사용되는 Http Client 입니다. 사용하기 간단하고 스프링5 이하 버전부터 많이 사용됐습니다. 동작방식은 멀티 스레드, 블로킹 방식을 사용하는데요.

 

스레드 풀에서 미리 스레드를 만들어 두었다가 사용자의 요청이 들어오면 각 스레드를 할당해주는 방식으로 사용됩니다. 블로킹 방식이기 때문에 하나의 스레드가 응답을 받을 때까지 해당 스레드는 사용할 수 없습니다. 만약에 동시 사용자가 많아지면 그만큼 스레드도 많이 필요하겠지요.

 

 

만약에 스레드가 부족해지면 Que에 요청을 대기시키고, 스레드의 작업이 끝나면 새롭게 요청을 할당 받습니다. 다만 Que에 요청대기가 시작되는 순간부터 서비스는 급격하게 느려지기 시작합니다.

 

 

RestTemplate 특징

  • 통신을 단순화하고 RESTful 원칙을 지킴
  • 멀티쓰레드 방식을 사용
  • Blocking 방식을 사용

 

 

의존성 설정

기본 스프링 부트 의존성을 추가하면 RestTemplate 관련 의존성은 자동으로 추가됩니다. 따라서 스프링 부트를 사용한다면 별다른 신경을 쓰지 않아도 된다고 합니다.

 

 

 

RestTemplate 사용 및 생성

RestTemplate을 생성할 때 어떤 HttpClient를 사용할 것인지 ClientHttpRequestFactory를 전달하여 지정할 수 있습니다. 

기본 생성자의 경우 내부적으로 ClientHttpRequestFactory 의 구현체 SimpleClientHttpRequestFactory를 사용하여 초기화 합니다.

 

@Configuration
public class RestTemplateClient {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }
}


RestTemplate을 생성할때는 builder를 통하여 생성해 줄 수 있습니다.
그리고 builder를 통해 생성하고 스프링 빈으로 사용할 수 있도록 설정해줍니다.

public class RestTemplateTestClass {
    @Autowired 
    RestTemplate restTemplate;

    public TestClass(RestTemplate restTemplate){
            this.restTemplate = restTemplate;
    }

    public String getSthFromServer(){
        return restTemplate.getForObject("https://example.com",String.class);
    }
}

 

 

RestTemplate을 사용하기 위해서는 restTemplate.메소드명() 을 사용하면 된다고 합니다.

 

 

 

 

WebClient

WebClient 란?

WebCleint는 스프링 5.0에서 추가된 인터페이스 입니다. WebClient도 RestTemplate와 마찬가지로 Http Client 인데요. RestTemplate와 다른점은 논블로킹, 단일 스레드 방식이라는 것입니다. cpu 코어 1개당 1개의 스레드를 사용합니다.

 

WebClient 특징

  • 싱글 스레드 방식을 사용
  • Non-Blocking 방식을 사용
  • JSON, XML을 쉽게 응답

 

의존성 설정

WebClient를 사용하기 위해서는 RestTemplate와 달리 의존성을 추가해야 할 부분이 있습니다. webflux 의존성을 추가해줘야 합니다. Gradle 기준으로 아래와 같이 의존성을 추가해주면 됩니다.

// webflux
implementation 'org.springframework.boot:spring-boot-starter-webflux'

 

 

WebClient 생성

WebClient를 생성하는 데는 2가지의 방법이 있습니다.

  • WebClient.create();
  • Builder를 활용한 클래스 생성
Webclient webClient = WebClient
                    .builder()
                    .baseUrl("http://localhost:8080")
                    .defaultCookie("쿠키","쿠키값")
                    .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                    .build();

 

 

  • Request요청하기
WebClient.RequestHeaderUriSpec<?> baseSpec = Webclient.builder()
.baseUrl("주소")
.build()
.get();

// baseSpec에 원하는 파라미터를 추가로 붙여서 요청한다. 
baseSpec.uri(builder -> builder.path("/")
                               .queryParam("이름","값")
                               .builder()
                        )
                        .retrieve() // Response를 받아옴.

 

 

 

 

Response 받아오기

response를 받아오는 방법에는 두 가지가 있습니다.

 

  • exchange() → ClientResponse를 상태값 그리고 헤더와 함께 가져 옵니다.
  • retrieve() → body를 바로 가져 옵니다.
String response = req.exchange().block().bodyToMono(String.class).block();
String response2 = req2.retrieve().bodyToMono(String.class).block();


bodyToMono 는 가져온 body를 Reactor의 Mono 객체로 바꿔줍니다. Mono 객체는 0-1개의 결과를 처리하는 객체이다. Flux는 0-N개의 결과를 처리하는 객체 입니다.

block() 을 사용하면 RestTemplate 처럼 동기식으로 사용할 수 있습니다.

 

 

RestTempalte 과 WebClient의 차이

RestTemplate과 WebClient의 가장 큰 차이점은 Non-Blocking과 비동기화 가능 여부일 것 입니다. 결국 이러한 차이점이 스프링에서 RestTemplate을 사용하는 것 보다 WebClinet의 사용을 권장하는 이유라고 생각합니다. 스프링 4.0에서 RestTemplate의 비동기 문제를 해결하기 위해 AsyncRestTemplate을 잠깐 사용하긴 했지만, 앞서 말한대로 현재 deprecated 된 상태라고 합니다.

 

 

더보기

Non-Blocking?

시스템을 호출한 직후에 프로그램으로 제어가 다시 돌아와서 시스템 호출의 종료를 기다리지 않고 다음 동작을 진행합니다.

호출한 시스템의 동작을 기다리지 않고 동시에 다른 작업을 진행할 수 있어서 작업의 속도가 빨라진다는 장점이 있습니다.

 

 

 

성능비교

RestTemplate와 WebClient 실험 보기

 

 

RestTemplate과 WebClient를 비교했을 때, RestTemplate은 15초 정도의 시간이 소요되는 반면, WebClient는 5~10초 내외로 훨씬 빠른 응답 속도를 보였습니다. 동시 사용자가 1,000명까지는 두 방식의 처리 속도가 거의 비슷하지만, 그 이후에는 RestTemplate(Boot1)이 급격하게 느려지는 현상이 발생했습니다.

 

따라서, 동시 사용자가 적은 규모에서는 RestTemplate을 사용하는 데 큰 문제가 없지만, 사용자 규모가 커질 경우 WebClient를 선택하는 것이 더 효율적이고 바람직합니다.

 

그렇다면 지금까지 RestTemplate로 사용했던것을 WebClient로 변경해야할까요? 🤔

 

이전까지 RestTemplate을 사용했다면 굳이 WebClient로 변경할 필요는 없을 것 같습니다. 하지만 새롭게 개발을 진행한다면 WebClient의 도입을 생각해봐야 합니다. WebClient는 RestTemplate이 할 수 있는 동기호출을 할 수 있고 비동기 호출도 가능합니다.

 

하지만 RestTemplate은 WebClient가 가능한 비동기 호출을 할 수 없다. RestTemplate을 사용한다면 응답이 올 때까지 계속 기다려야 할 것이다.

 

 

 

정리하자면

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

 

 

 

 

 

reference

https://madplay.github.io/post/difference-between-resttemplate-and-webclient

https://www.baeldung.com/spring-webclient-resttemplate

https://weight-devlog.tistory.com/46#RestTemplate%EB%9E%80%3F-1

https://velog.io/@emotional_dev/RestTemplate-vs-WebClient

https://tecoble.techcourse.co.kr/post/2021-07-25-resttemplate-webclient/