[스프링 웹플럭스] 1.1.6. 서버 선택하기

https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-server-choice

스프링 웹플럭스는 네티, 언더토우, 톰캣, 제티와 서블릿 3.1+ 컨테이너를 지원한다. 모두 리액티브 스트림 API를 채용했다. 스프링 웹플럭스 프로그래밍 모델은 그러한 공통 API에 기반하여 만들었다.

자주 받는 질문: 톰캣이랑 제티를 어떻게 두 가지 스택에서 다 쓸 수 있는거지?

톰캣과 제티의 코어 자체는 논-블러킹이다. 하지만 서블릿 API가 그 위에 블럭킹 퍼사드를 추가했다. 서블릿 3.1 API부터 논-블럭킹 I/O를 제공하는 선택지를 제공하지만 그것을 사용하려면 다른 동기적이고 블럭킹 요소를 피하도록 주의해야 한다. 그러한 이유로 스프링의 리액티브 웹 스택은 리액티브 스트림과 연결해주는 로우 레벨 서블릿 어댑터을 가지고 있으며 서블릿 API를 노출 시키지 않아서 직접 사용할 수 없도록 했다.

스프링 부트 2는 웹플럭스를 사용할 때 네티를 기본으로 사용한다. 왜냐면 네티가 비공기, 논-블럭킹 영역에서 가장 널리 사용되고 있으며 클라이언트과 서버 모두 공유할 수 있는 리소스를 제공한다. 서블릿 3.1 논-블럭킹은 아직 많이 사용되지 않았는데 쓰기 어렵기 떄문이다. Spring WebFlux opens one practical path to adoption. (?)

스프링 부트가 기본 서버를 선택할 때 주로 바로 사용할 수 있는 것(out-of-the-box)을 선택한다. 애플리케이션은 여전히 성능 최적화 되어있고, 완전히 논-블럭킹이고 리액티브 백 프레셔를 채택한 어떤 서버든 선택할 수 있다. 스프링 부트에서 매우 손쉽게 서버를 바꿀 수 있을 것이다.

[스프링 웹플럭스] 1.1.5. 웹 프레임워크 선택하기

https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-programming-models

스프링 MVC를 써야 하나 웹플럭스를 써야 하나? 차이점을 살펴보자.

이미 동작하는 스프링 MVC 애프리케이션이 있다면 그대로도 괜찮다. 바꿀 필요는 없다. 절차적인 프로그래밍은 가장 쉽게 작성하고, 이해하며 디버깅할 수 있는 코드다. 역사적으로 대부분이 블럭킹인 수많은 라이브러리를 선택해 사용할 수 있다.

논-블럭킹 웹 스택을 이미 살펴보고 있다면, 스프링 웹플럭스는 그 영역에서 다른 것들과 동일한 실행 모델을 제공하며 서버를 선택해 사용할 수 있게끔 해준다. 네티, 톰캣, 제티, 언더토우, 서블릿 3.1+ 컨테이너를 사용할 수 있다. 프로그래밍 모델로는 애노테이션 컨트롤러와 펑셔널 웹 엔드포인트 그리고 리액터, RxJava 등의 리액티브 라이브러리를 선택해 사용할 수 있다.

가벼운 펑셔널 웹 프레임워크를 자바 8 람다나 코틀린으로 사용하고 싶다면 스프링 웹 플럭스 펑셔널 웹 엔드포인트를 사용할 수 있다. 작은 애플리케이션이나 복잡도가 낮은 마이크로서비스용으로 사용하여 투명성과 제어에 대한 장점을 살릴 수 있다.

마이크로서비스 아키텍처 안에서 스프링 MVC 애플리케이션과 스프링 웹플럭스 컨트롤러 또는 스프링 웹플럭스 펑셔널 엔드포인트를 혼용할 수 있다. 똑같은 애노테이션 기반의 프로그래밍 모델을 양쪽 프레임워크 모두에 사용함으로써 기존 지식의 재사용을 편하게 하며 적절한 곳에 적절한 툴을 선택해 사용하게 해준다.

애플리케이션을 평가하는 쉬운 방법중 하나는 의존성을 확인하는 것이다. 만약에 블록킹 영속화 API (JPA, JDBC)를 사용하거나 네트워크 API를 사용한다면 스프링 MVC가 가장 흔한 아키텍처로는 최적이다. 기술적으로는 리액터나 RxJava로도 블럭킹 호출을 별도의 쓰레드로 처리하는게 가능하지만 대부분의 논-블럭킹 웹 스택에서는 그런 쓰레드를 만들지 않는다.

리모트 서비스를 호출하는 스프링 MVC 애플리케이션이 있다면 리액티브 WebClient를 사용해보자. 스프링 MVC 애플리케이션 메서드에서 리액티브 타입 (리액터, RxJava, 그리고 다른 것)을 직접 반환할 수 있다. 호출 당 지연이 크거나 상호 의존도가 클 수록 효과를 크게 볼 수 있다. 스프링 MVC 컨트롤러는 다른 리액티브 컴포넌트를 호출할 수 도 있다.

대규모 팀이라면 논-블럭킹과 선언적인 프로그래밍으로 옮기는데 드는 학습 비용을 염두해야 한다. 실용적인 방법은 전체를 전화하는게 아니라 리액티브 WebClient를 사용하는것 부터 시작하는 것이다. 조금씩 바꾸기 시작한 다음 그 효과를 측정하라. 애플리케이션 전체를 다 바꿀 필욘 없을 것으로 예상한다.

어떤 장점을 얻을 수 있는지 확실하지 않다면, 논-블럭킹 I/O의 동작 방법(단일 쓰레드 Node.js의 동시성은 모순이 아니다.)과 그 효과에 대해 학습하라. 주목할 점은 “하드웨어는 조금 쓰면서 확장하는 것”이지만 느리거나 예측 불가능한 어느정도의 네트워크 I/O 없이는 그 효과를 보장하진 않는다. 넷플릭스의 이 블로그가 참고하기 좋다.

[스프링 웹플럭스] 1.1.2. 리액티브란 무엇이며 왜?

https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-why-reactive

논-블럭킹과 펑셔널에 대해 언급했는데 왜 리액티브를 해야 하며 그게 무슨 의미가 있을까?

“리액티브”라는 단어는 I/O 이벤트에 반응하는 네트워크 컴포넌트, 마우스 이벤트에 반응하는 UI 컨트롤러 등 어떤 변화에 반응하는 것을 아우르는 프로그래밍 모델을 뜻한다. 그런 점에서 논-블럭킹은 반응형이다 왜냐면 블럭킹되지 않고 작업이 완료되거나 데이터가 전달되는 등의 알림에 반응하는 모델 속에 있기 떄문이다.

우리가 스프링 팀에서 “리액티브”와 더불어 중요하게 여기는 매커니즘 하나가 바로 논-블럭킹 백 프레셔(back pressure)다. 동기적이고, 순차적인 코드, 블럭킹 콜은 자연적으로 백 프레셔를 제공한다. 왜냐면 호출한 쪽이 그 작업이 끝날 때까지 기다려야 하니까. 하지만 논-블럭킹 코드에서는 이벤트를 공금하는 쪽(publisher)이 지나치게 빨라서 그걸 소비하는 쪽이 뻗지 않게 이벤트 비율을 조절하는것이 중요해진다.

리액티브 스트림은 작은 규모의 스팩이고 자바 9가 채용했다. 플로우 API로 비동기적인 컴포넌트간의 백 프레셔를 고려한 상호 교류를 정의했다. 예를 들어, 데이터 저장소는 발행자처럼 동작하며 데이터를 공급할 수 있다. 그리고 그 데이터를 구독자처럼 동작하는 HTTP server가 받아서 응답을 작성할 수 있다. 리액티브 스트림의 주요 목적은 구독자로 하여금 얼마나 빨리 또는 느리게 공급자가 데이터를 생성해야 하는지 제어할 수 있게끔 하는 것이다.

자주받는 질문: 발행자를 늦출 수 없으면?
리액티브 스트림의 목적인 오로지 그러한 매커니즘과 경계를 만들는 것 뿐이다. 만약에 발행자를 늦출 수 없다면 버퍼에 담을지, 버릴지, 실패할지 정해야 한다.

[스프링 웹플럭스] 1.1.4. 프로그래밍 모델

https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-programming-models

spring-web  모듈은 스프링 웹플러스가 올라가는 리액티브 기반 시설을 포함하고 있다. HTTP 추상화, 리액티브 스트림 서버 어댑터, 리액티브 코덱과 핵심 웹 API가 있다. 웹 API는 서블릿 API와 비슷하자먼 논-블럭킹용이다.

그 기반 시설 위에서 스프링 웹플럭스는 두가지 프로그래밍 모델을 제공한다.

  • 애노테이션 컨트롤러 – 스프링 MVC와 동일하며 spring-web 모듈에서 제공하는 것과 동일한 애노테이션에 기반하고 있다. 스프링 MVC와 웹플럭스 컨트롤러 모두 리액티브 (Reactor, RxJava) 리턴 타이을 지원하기 때문에 따로 분리해서 말하긴 어렵다. 주목할만한 차이라면 웹플러그는 리액티브 @RequestBody 인자로 지원한다.
  • 함수형 Endpoint – 람다 기반의 가벼운 함수형 프로그래밍 모델이다. 애플리케이션이 요청을 라우팅하고 처리 할 때 사용할 수 있는 작은 라이브러리나 유틸리티 셋으로 생각할 수 있다. 애노테이션 컨트롤러와의 큰 차이점은 애플리케이션이 요청 처리의 처음부터 끝까지 책임진다는 점이다. 애노테이션 컨트롤러에서는 애노테이션으로 인텐트를 표현하고 컨트롤러의 코드는 프레임워크에서 나중에 호출(콜 백)되는 식이었던과 비교할 수 있다.

 

[스프링 웹플럭스] 1.1.3. 리액티브 API

https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-reactive-api

리액티브 스트림은 상호 호환성에 있어서 중요한 역할을 한다. 라이브러리나 기반 컴포넌트로써 중요한 역할을 하지만 애플리케이션 API로써는 유용하지 않다 왜냐면 상당히 로우 레벨이기 때문이다. 애플리케이션이 필요로 하는것은 보다 상위 레벨의 풍부하며 비동기 로직을 조합하는데 사용할 함수 API 같은 것이다. 자바 8의Stream API와 비슷하지만 컬렉션에 국한되진 않은 것이 필요하다. 바로 그러한 역할을 리액티브 라이브러리가 할 것이다.

스프링 웹플럭스에서 선택 리액티브 라이브러리는 리액터다. 리액터는 리액티브엑스의 다양한 오퍼레이터에 해당하는 풍부한 기능 셋을 통해 0..1과 0..N 개의 데이터 시퀀스를 다룰 수 있는 MonoFlux API 타입을 제공한다. 리액터는 리액티브 스트림 라이브러리의 일종이며 따라서 그 모든 오퍼레이터는 논-블럭킹 백 프레셔를 지원한다. 리액터는 서버 사이드 자바에 집중하고 있다. 스프링과 긴밀하게 협업하며 개발되었다.

웹플럭스는 리액터를 핵심 의존성으로 필요로 하지만 다른 리액티브 스트림 라이브러리로 교체할 수 있다. 일반적으로 웹플럭스 API는 평범한  Publisher를 입력값으로 받고 내부적으로 리액터 타입으로 변환하여 사용하고 Flux 나 Mono 를 결과값으로 반환한다. 따라서 여러분은 어떠한 Publisher라도 입력값으로 전달할 수 있으며 결과값에 오퍼레이션을 적용할 수 있다. 하지만 다른 라이브러리를 사용한다면 결과값을 다른 리액티브 라이브러로 변환해야 할 것이다. 가능한한 애노테이션을 사용한 컨테이너처럼, 웹플럭스는 투명하게 RxJava나 다른 리액티브 라이브러리를 사용할 수 있다. 자게한 내용은 리액티브 라이브러리를 참고하라.