Spring에서 두 개의 프로젝트간 API 통신을 하려는 과정에서 Spring에서 제공하는 WebClient를 사용할 일이 생겨 정리해보려고 한다.
작동 방식과 디자인에 대해서 단계별로 알아보자.

일단 들어가기 전에 사전지식으로 동기와 비동기, 블로킹과 논블로킹 방식에 대해 알아야한다.
Blocking vs Non-Blocking은 다른 주체가 작업을 할때 제어권이 있는지 없는지로 판단한다.
Sync vs Async는 호출된 함수의 종료를 신경쓰는 주체가 누구냐에 따라 갈린다.
보면 알겠지만 Sync-NonBlocking이나 Async-Blocking은 다소 비효율적으로 보인다. 폴링방식은 설계상 어쩔 수 없이 채택하기도 하지만, Async-Blocking은 쓸 이유가 없다.

스프링에서 위 두 스택중 하나를 선택하여 섞지 않고 적용해야 각 디자인이 가지는 장점을 확실하게 가져갈 수 있다.

Spring MVC 경우 Multi-Thread + Blocking 방식을 사용한다.
클라이언트의 요청당 서버는 Thread pool에서 남는 Tread를 하나씩 할당하고 부족하면 큐에서 대기 시킨다.
이때 Tread의 개수와 컴퓨터 성능의 적절한 비율이 맞아야 높은 효율을 가질 수 있다.

Spring Webflux의 경우 Single-Thread + Non-Blocking 방식을 사용한다.
원시적으로 spring은 멀티 스레드로 병렬처리를 했으나, 위와 같이 아무리 컴퓨터 성능이 좋아도 스레드 개수의 제한에 의해 한계가 있었다.
이를 좀 더 효율적으로 사용하고자 Reactive Programming을 적용한 것이다.(자바 라이브러리로 Reactors나 RxJava같은 것이 있다.) Non-Blocking 방식이기에 하나의 스레드를 점유하지 않고 동시에 많은 작업을 사용할 수 있다.
이는 성능이 무조건 좋아진다는 이야기는 아니다. '고가용성'을 보장해준다는 이야기이다. (오히려 어플리케이션의 성능 자체는 반대로 나빠질 수도 있으나, 작은 고정된 수의 스레드와 적은 메모리에서도 최대한의 효율을 내면서 확장 가능하다.)
대규모 서비스에 그만큼 적합한데 배민에서 적용한 사례도 찾아볼 수 있었다. https://techblog.woowahan.com/12903/
리액티브 프로그래밍은 데이터 스트림과 변화의 전파에 관련된 선언적 프로그래밍 패러다임이다. 밑의 코드로 예시를 보자.
// 명령형 ex1
변수 b = 1
변수 c = 2
변수 a = b + c
b = 10
console.log(a) // 3 ("="은 반응 할당 연산자가 아니기 때문에 12가 아님)
// ex2
@Test
@DisplayName("명령형 프로그래밍")
void 명령형_예제()
{
String name = "Craig";
String capitalName = name.toUpperCase();
String greeting = "Hello, " + capitalName + "!";
System.out.println(greeting);
}
// 선언형
// 이제 명시적으로 초기화될 때뿐만 아니라 참조된 변수(연산자의 오른쪽)가 변경될 때 변수의 값을 변경하는 특수 연산자 "$="가 있다고 상상해 보세요.
변수 b = 1
변수 c = 2
var a $= b + c
b = 10
console.log(a) // 12
//ex2
@Test
@DisplayName("선언형 프로그래밍")
void 선언형_예제()
{
Stream.of("Crag")
.map(String::toUpperCase)
.map(cn -> "Hello, " + cn + "!")
.forEach(System.out::println);
}
구체적으로 실행 방법을 명시하는 명령형 프로그래밍(how to do)과 달리 목표만을 정의하는 선언적 프로그래밍 방식(what to do)을 지원한다. 자바의 스트림이 일종의 선언적 프로그래밍이라고 볼 수 있다. 이처럼 데이터 스트림을 선언해두고 데이터가 변화(이벤트)하면 이걸 전파만 해서 자동으로 업데이트한다.
사실 두 구조나 설정은 대부분 동일하다. 그러나 MVC에서는 어플리케이션이 스레드를 차단할 수 있다면, 넓은 스레드 풀을 사용하게 되며, WebFluxs 스레드를 차단하지 않아, 적은 스레드풀을 활용해 request들을 처리한다.
Spring Webflux는 JVM 위에서 리엑티브 프로그래밍을 가능하게 해주는 라이브러리 Reactor를 활용하고 있다.
Webflux는 데이터 스트림을 두가지 타입으로 정의하는데 아래와 같다.
WebClient : Spring WebFlux에서 HTTP Client로 사용되는 비동기적으로 작동하는 모듈이다.
Java에서 많이 쓰던 Http Client는 RestTemplate이다. 그러나 Spring은 5.0버전부터 해당 WebClient사용을 강력히 권고하고 있다.
여기서 RestTemplate가 Multi-Thread + Blocking 방식이며, WebClient가 Single-Thread + Non-Blocking방식으로 해석할 수 있다.
심지어 WebClients는 블로킹으로도 사용가능해서 앞으로 api통신에 이를 활용할 것이다.
https://velog.io/@rnqhstlr2297/Spring-Webflux와-WebClient
https://gngsn.tistory.com/154
https://taes-k.github.io/2019/05/21/about-spring-reactive/
https://velog.io/@salgu1998/Reactive-Programming리액티브-프로그래밍-이란
https://velog.io/@suhongkim98/명령형-프로그래밍-선언형-프로그래밍-리액티브-프로그래밍-리액티브-시스템..-1
https://devocean.sk.com/blog/techBoardDetail.do?ID=165099&boardType=techBlog