title: Spring RestTemplate vs WebFlux
date: 2023-05-20
tags:
- Spring
Introduction
외부 API 호출 시 RestTemplate과 WebFlux 중 한 가지를 최종적으로 선택하여야 하는 상황이었다.
두 가지 모두 처음 사용하기에 모두 이용한 후 종합적으로 판단하기로 결정하였다.
RestTemplate
RestTemplate은 Spring 3.0에서 도입되었다.
2000년대 말 도입이지만, 안정적인 시스템이 중요한 현업에서는 2010년대에 도입이 되었을 것이다.
그렇지만 간단하게 사용할 수 있으며, WebFlux에 비하면 오래된 기술이기에 유지 보수 측면에서는 더욱 좋다고 판단하였다.
public ResponseEntity<String> fetchBookFromNaverApi(String keyword, boolean searchRecent) {
String naverBookApiUrl = "https://openapi.naver.com/v1/search/book_adv.xml?d_catg=280&d_titl=" + keyword;
if (searchRecent) {
naverBookApiUrl += "&sort=date";
}
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("X-Naver-Client-Id", keys.getNaverClientId());
httpHeaders.set("X-Naver-Client-Secret", keys.getNaverClientSecret());
HttpEntity<String> entity = new HttpEntity<>(httpHeaders);
return restTemplate.exchange(naverBookApiUrl, HttpMethod.GET, entity, String.class);
}
Header 및 Method만 명시하면 ResponseEntity로 받아올 수 있다.
Synchronous 및 Block 방식으로, Asynchronous 및 Non-Block을 원한다면 WebFlux를 사용해야 한다.
WebFlux
WebFlux는 Spring 5.0에서 도입된 최신 기술이다.
Reactive Programming을 기반으로 하며, Asynchronous 및 Non-Block 방식으로 작동 가능하다.
최신 기술이며 Asynchronous 및 Non-Block이 가능하기에 성능 측면에서 이점이 있겠으나, 이 경우 관리가 어려워진다.
또한 Spring 5.x를 쓰지 않는 한 WebFlux를 사용할 수 없기에, 아직까지는 현업에서 적극적으로 활용되지 않을 가능성이 높을 것이다.
public ResponseEntity<String> fetchWebFlux(String keyword, boolean searchRecent) {
String naverBookApiUrl = "https://openapi.naver.com/v1/search/book_adv.xml?d_catg=280&d_titl=" + keyword;
if (searchRecent) {
naverBookApiUrl += "&sort=date";
}
return = webClient.get()
.uri(naverBookApiUrl)
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.toEntity(String.class)
.block();
}
Non-Block에서 원하는 대로 동작하지 않아 우선 Block 방식으로 이용하고 있었다.
Time Comparison
본 기능은 네이버 API를 이용하여 서적 검색 -> 서적 추가를 위한 기능이기에 성능이 크게 중요하지는 않다.
각 Method를 수정하였으며, 시작부터 끝까지 시간을 측정하여 성능을 비교하였다.
또한 동일한 Keyword를 이용하여 Caching이 될 수도 있기에, 매번 다른 Keyword를 이용하여 최대한 운영 환경에 가깝게 설정하였다.
void fluxRestTimeTest() throws InterruptedException {
long fluxTime = 0L;
long restTime = 0L;
String[] temp = new String[]{"자바", "C", "파이썬", "스크래치", "비동기", "동기", "패턴", "아키텍쳐", "가이드", "C++"};
for (int i = 0; i < 10; ++i) {
long tempFlux = adminService.fetchWebFlux(temp[i], false);
fluxTime += tempFlux;
long tempRest = adminService.fetchBookFromNaverApi(temp[i], false);
restTime += tempRest;
log.info("flux : {}, rest : {}", tempFlux, tempRest);
Thread.sleep(1000);
}
log.info("total flux : {}, average flux : {}", fluxTime, fluxTime / 10);
log.info("total rest : {}, average rest : {}", restTime, restTime / 10);
}
sleep은 두 가지 목적으로 이용하였다.
우선 sleep이 없다면 너무 빠른 API 호출로 인하여 429 Too Many Requests 에러가 발생한다.
또한 운영 환경에서는 사람이 진행하거나, 키워드를 미리 주입하여 배치 처리를 할 것이다.
전자라면 더욱 긴 시간을 기다려야 할 것이며, 후자라면 데이터 Parsing & Mapping, DB에 저장까지 하므로 텀이 존재한다.
위 사진은 하나지만, 여러 번 측정을 진행하였다.
WebFlux의 초기 호출은 평균적으로 450 ~ 500ms의 시간이 소요되었다. 이후 호출은 사진과 같이 RestTemplate과 비슷한 성능을 보여주었다.
이에 반해 RestTemplate의 초기 호출은 평균적으로 150 ~ 200ms의 시간이 소요되었으며, 이후 호출은 WebFlux처럼 짧은 시간을 기록하였다.
WebFlux가 Block 방식으로 동작하더라도 RestTemplate보다 빠를 줄 알았으나, RestTemplate과 비슷한 성능을 보여준다.
호출이 반복되더라도 성능이 비슷하며, 초기 호출은 WebFlux가 훨씬 크기에 현재 상황에서의 성능은 RestTemplate이 더욱 좋다.
WebFlux를 Asynchronous Non-Block으로 동작하도록 설정하면 더욱 빨라질 수 있을 것 같다.
Conclusion
현재 구성으로는 성능 측면에서 WebFlux를 사용할 근거를 찾을 수 없다.
또한 이전에 언급하였듯이, RestTemplate이 유지 보수 측면에서 더욱 좋다고 판단하였기에 최종적으로 RestTemplate으로 전환하게 되었다.
다만 트래픽이 증가하여 신규 서적 관리에 대한 공수 및 Server의 부하가 커질 경우, WebFlux로 다시 전환하여 배치 처리를 하는 것이 더욱 좋을 것 같다.
하지만 이는 먼 미래이기에, 우선순위가 높은 기능에 먼저 집중한다.
'Spring' 카테고리의 다른 글
Spring에서 JdbcTemplate Test 시 Parameter 나열 문제 (0) | 2023.06.01 |
---|---|
Spring RestTemplate Test (0) | 2023.05.29 |
Spring의 RestTemplate에서 GET 이용 시 Header 설정 (0) | 2023.05.20 |
Spring에서 정적 파일 로딩 시 ERR_ABORTED 404 (0) | 2023.05.18 |
Spring에서 yml 파싱 (0) | 2023.05.11 |