백엔드개발자로 주로 클라이언트 요청을 받아 비즈니스 로직을 처리해 응답하는 부분을 처리하지만, 서버에서도 외부 API를 사용하는 등 Http 요청을 통해 정보를 얻는 경우도 필요합니다.
지금까지 진행한 프로젝트에서는 이 부분을 깊게 공부할 시간이 없어 모두 Spring이 제공하는 RestTemplate을 사용했지만 기반이 되는 부분을 조금 더 공부한 내용을 정리하기 위한 글입니다.
RestTemplate
Spring3.0부터 간편하게 동기식 Rest API 호출을 할 수 있게 해주는 클래스(Spring MVC 기반)입니다.
JSON, XML, String 응답을 처리할 수 있고 Header와 Contetn-Type을 지정할 수 있습니다.
Header, Content-Type 지정은 exchange()의 파라미터로 원하는 정보를 가진 HttpEntity를 사용해 추가 가능합니다.
RestTemplate docs
WebClient
Spring5.0부터 Non-blocking한 방식을 지원하고 리액티브 타입(Mono, Flux)의 전송과 수신을 지원하는 인터페이스(Spring WebFlux 기반)입니다. Stream 결과의 전체를 받는 Mono와 Stream을 개별적으로 컨트롤하는 Flux, 함수형 인터페이스들로 유연하고 리액티브하게 처리할 수 있습니다. Blocking 방식도 지원합니다.
비동기 프로그래밍
Client의 요청에 의해 RestTemplate을 사용하지만 API 호출 결과과 Client의 응답으로 이어지지 않고, 처리시간이 오래 걸리는 로직은 Client 요청과 분리해서 멀티쓰레드로 처리했습니다. WebClient에서는 어떻게 처리할 수 있을까 궁금했습니다.
RestTemplate(Spring MVC)
일의 처리 순서를 보장하기 위해 일을 수행하는 동안 블로킹 됩니다. MVC 기반 RestTemplate 동작방식과 같습니다.
멀티쓰레드를 사용한다면 동기 방식을 비동기적으로 사용할 수 있습니다.
일의 처리 순서를 보장하는 동기 방식이지만, 스레드를 빌려와 일을 처리하면 RestTemplate도 비동기적으로 사용할 수 있습니다. 하지만 스레드풀에서 스레드를 빌려오는 비용, 스레드 교체하는 비용, 레이스 컨디션을 고려해야합니다.
WebClient .subscribue of Webflux(Non-Blocking I/O)
같은 쓰레드에서 논블로킹으로 일을 동시에 처리하기 때문에 먼저 시작한 일이여도, 더 나중에 처리 될 수 있습니다.
현재 백엔드에서 추세는 스레드를 적게 사용하면서 Non-Blocking I/O를 통해 전체적인 처리량을 늘리는 방향으로 발전중입니다. 요청을 Reactor Secheduler가 받아 실행중인 Thread의 Event Loop에 Job을 추가하거나, Thread를 빌려와 처리하는 Spring WebFlux의 추구 방향과 일치합니다.
정리
대용량 요청의 비동기 처리에서 스레드풀의 한계로 인해 MVC보다 Non-Block을 지원하는 WebFlux이 적은 스레드와 리소스를 사용해 효과적인걸 알게 됐습니다. 가상 OS 보다는 애플리케이션 추상화인 Docker, Servlet들 보다는 하나의 Dispatcher Servlet과 Controller 등과 같이 한정적인 자원을 효율적으로 사용하기 위한 진화과정이라고 생각합니다.
WebClient가 블로킹, 논블로킹을 모두 지원하지만 Spring Webflux를 강제로 의존하게 됩니다. Servlet API 기반의 프로젝트였거나 동기적 처리가 필요해 모든 요청을 블로킹으로 처리할 경우 Spring 6.0부터는 WebClient와 사용방법이 유사한 MVC 기반의 RestClient를 사용하시면 됩니다.
참고
https://www.youtube.com/watch?v=EJNBLD3X2yg&t=542s