💡 Webflux는 Spring Framework 5.0부터 지원한다고 들었는데 Spring Boot는 몇 버전이 되어야 하는가?
- Spring Framework 5.0은 Spring Boot 2.0 이상을 요구하므로 Webflux를 사용하는데 Spring Boot 2.0 이상 버전이 최소 요구사항이 됩니다.
2) Webflux 주요 특징
💡 Webflux는 ‘반응형 프로그래밍(Reactive Programming)’을 구현하기 위해 Reactor라는 라이브러리를 이용합니다. Reactor는 Netty 서버를 통해 비동기식 이벤트 기반의 서버를 환경을 제공하며 이를 이용하여 비동기 방식의 논 블로킹 요청을 통해 이벤트 기반의 반응형 스트림으로 데이터를 주고받습니다.
1. 반응형 프로그래밍(Reactive Programming)
💡 반응형 프로그래밍(Reactive Programming)
- Spring Webflux는 반응형 프로그래밍(Reactive Programming) 방식을 통해 ‘이벤트 기반의 비 동기식 애플리케이션’을 구축할 수 있습니다. - 이 이벤트는 ‘비 동기적’으로 처리되며 새로운 이벤트가 발생하면 이벤트 스트림이 생성이 되며 스트림을 구독하면 이벤트를 처리할 수 있습니다.
[ 더 알아보기 ]
💡 프로그래밍 패러다임으로 본 명령형 프로그래밍 vs 반응형 프로그래밍
- 명령형 프로그래밍의 경우는 컴퓨터가 수행해야 하는 일을 명령의 목록으로 나열을 하고 이를 순서대로 실행합니다. 반응형 프로그래밍의 경우는 데이터 스트림을 처리하며 이 데이터 스트림이 변경될 때마다 반응하는 것을 의미합니다.
- 반응형 프로그래밍(Reactive Programming)을 구현하기 위한 Reactor는 Reactive 라이브러리 중 하나입니다. - Publisher-Subscriber 패턴을 중심으로 동작하며 데이터를 생성하고 가공하고 구독자에게 전달하는 역할을 합니다. - Reactor에서는 Mono와 Flux의 데이터 스트림 유형을 지원합니다.
2. [onSubscribe] Publisher가 Subscriber에게 데이터 스트림을 ‘전송하기 시작하기 전에 호출’됩니다. 이 메서드를 통해 Subscriber는 Subscription 객체를 받아들여 데이터의 양을 제어할 수 있습니다.
3. [request(n)/cancel] request(n) 메서드는 Publisher에게 n개의 데이터를 요청하고, cancel 메서드는 데이터 스트림을 취소합니다.
4. [onNext(data)] Publisher가 ‘생성한 데이터’를 Subscriber에게 전달합니다. 이 메서드는 데이터가 전송될 때마다 호출됩니다.
5. [onComplete/onError] Publisher가 모든 데이터를 전송하고, 더 이상 데이터가 없을 때 호출됩니다.
- onComplete 메서드는 모든 데이터가 성공적으로 전송되었음을 나타냅니다. - onError 메서드는 데이터 전송 중 오류가 발생했음을 나타냅니다.
[ 더 알아보기 ]
💡 이벤트(Event)
- 구독자(Subscriber)가 발행자(Publisher)에게 데이터를 요청하고 발행자가 데이터를 생성하고 전송하는 것을 의미합니다. 구독자가 요청을 한 후 발행자는 데이터를 생성하고 onNext(data) 메서드를 사용하여 구독자에게 데이터를 전달합니다. 구독자는 request(n) 메서드를 사용하여 발행자에게 추가 데이터를 요청할 수 있습니다.
💡 백프레셔(BackPressure)
- 비동기 스트림 처리에서 ‘데이터의 양을 제어’하는 것을 의미합니다. 발행자(Publisher)가 생성한 데이터를 구독자(Subscriber)가 처리할 때 구독자가 처리할 수 있는 데이터 양을 초기화하여 데이터가 생성되는 상황을 방지하기 위해 백 프레셔를 사용합니다.
- 백프레셔는 Subscriber가 처리할 데이터의 양을 Subscription을 통해 제어하며, Publisher는 Subscriber의 처리 속도에 맞춰 데이터를 생성합니다. 이를 통해 Subscriber가 처리할 수 있는 양 이상의 데이터가 생성되는 상황을 방지하고, 시스템의 안정성을 보장할 수 있습니다.
2.3. Mono
💡 Mono - Reactor 라이브러리에서 제공하는 Reactive Streams의 Publisher 중 하나로 오직 ‘0개 또는 하나의 데이터항목 생성’하고 이 결과가 생성되고 나면 스트림이 종료되면 결과 생성을 종료합니다. - Mono를 사용하여 비동기적으로 결과를 반환하면 해당 결과를 구독하는 클라이언트는 결과가 생성될 때까지 블로킹하지 않고 다른 작업을 수행할 수 있습니다.
메소드
설명
just()
주어진 데이터를 포함하는 Mono를 생성합니다.
empty()
데이터가 없는 Mono를 생성합니다.
error()
에러 상황을 나타내는 Mono를 생성합니다.
fromCallable()
Callable 객체를 이용해 Mono를 생성합니다.
fromFuture()
Future 객체를 이용해 Mono를 생성합니다.
fromRunnable()
Runnable 객체를 이용해 Mono를 생성합니다.
💡 [ Mono 사용 예시 ]
- "Hello, world!"라는 문자열을 Mono.just를 통해 Mono로 만든 후, map 연산자를 이용해 문자열을 대문자로 변환합니다. - 이후, flatMap 연산자를 이용해 "Mono: "이라는 문자열과 결합합니다. - 마지막으로, 비동기적으로 처리된 결과값을 subscribe 메서드를 이용하여 출력합니다.
- Reactor 라이브러리에서 제공하는 Reactive Streams의 Publisher 중 하나로 Mono와 달리 ‘여러 개의 데이터 항목’를 생성하고 스트림이 종료되면 결과 생성을 종료합니다.
- 비동기 작업을 수행하면 작업이 완료될 때까지 블로킹하지 않고 다른 작업을 수행할 수 있습니다. - Spring WebFlux에서 Flux를 사용하여 HTTP 요청을 처리하는 경우, 요청을 수신한 즉시 해당 요청을 처리하고 결과를 생성하는 대신 결과 생성이 완료될 때까지 다른 요청을 처리할 수 있습니다.
메소드
설명
just()
주어진 데이터를 포함하는 Flux를 생성합니다.
fromIterable()
Iterable 객체를 이용해 Flux를 생성합니다.
fromArray()
배열을 이용해 Flux를 생성합니다.
fromStream()
Stream을 이용해 Flux를 생성합니다.
empty()
데이터가 없는 Flux를 생성합니다.
error()
에러 상황을 나타내는 Flux를 생성합니다.
range()
지정된 범위의 정수를 포함하는 Flux를 생성합니다.
interval()
일정 시간 간격으로 값을 생성하는 Flux를 생성합니다.
merge()
여러 개의 Flux를 병합하여 하나의 Flux로 만듭니다.
concat()
여러 개의 Flux를 순차적으로 이어붙여 하나의 Flux로 만듭니다.
zip()
여러 개의 Flux를 조합하여 튜플 형태로 만듭니다.
collectList()
Flux에 포함된 모든 데이터를 리스트로 수집합니다.
collectMap()
Flux에 포함된 모든 데이터를 맵으로 수집합니다.
💡 [ Flux 예시 ]
- "apple", "banana", "cherry" 세 문자열을 Flux.just를 통해 Flux로 만든 후, map 연산자를 이용해 문자열을 대문자로 변환합니다. - 이후, flatMap 연산자를 이용해 "Flux: "이라는 문자열과 결합합니다. - 마지막으로, 비동기적으로 처리된 결과값을 subscribe 메서드를 이용하여 출력합니다.
💡 Netty - 자바 기반의 네트워크 애플리케이션 프레임워크로 ‘비동기식 이벤트 기반 서버’를 만드는 데 사용이 됩니다. - 높은 성능과 확장성을 갖추고 있으며, 다양한 프로토콜을 지원하고 있어 네트워크 애플리케이션 개발에 매우 유용합니다.
[ 더 알아보기 ] 💡 Netty와 Tomcat의 비교
특성
Netty
Tomcat
아키텍처
이벤트-기반
요청 당 쓰레드
성능
비동기 처리로 인한 높은 성능
동기 처리로 인한 상대적으로 느린 성능
확장성
다수의 동시 접속 처리가 가능한 높은 확장성
쓰레드 개수 제한으로 확장성 한계
프로토콜 지원
HTTP, WebSocket, TCP 등 다수의 프로토콜 지원
주로 HTTP에 특화
유연성
다양한 애플리케이션에 사용 가능한 높은 유연성
웹 애플리케이션에 특화된 제한된 유연성
사용 편의성
이벤트-기반 아키텍처로 인한 학습 곡선이 높음
전통적인 서블릿 기반 아키텍처에 익숙한 개발자에게 사용하기 편리
4. Blocking Request / Non-Blocking Request
💡 일반적으로 Webflux를 사용하는 경우 Non-Blocking Request를 사용하는 것이 좋습니다. Blocking Request를 사용하면 스레드가 차단되어 성능이 저하되기 때문입니다. 💡 WebFlux는 Reactive Programming 모델을 위해 설계되었으며, Non-Blocking Request를 사용하면 이러한 모델을 더욱 효과적으로 활용할 수 있습니다.
💡 Blocking Request (=Synchronous request)
- 기존 Spring MVC에서 사용되던 Blocking Request를 수행하면서 클라이언트에서 요청을 보내면 결과가 반환될 때까지 대기를 하는 것을 의미합니다.
💡 WebClient - WebFlux의 일부인 Webclient는 비동기적인 방식으로 HTTP 요청을 보내고 응답을 받을 수 있는 라이브러리를 의미합니다. - 다수의 외부 API 호출이나, 다른 서비스들과의 통합 작업에서 유용합니다. - WebFlux의 WebClient는 비동기적인 방식으로 HTTP 요청을 보내고 응답을 받을 수 있는 라이브러리입니다. 이를 통해 Reactive Streams를 이용하여 높은 성능의 네트워크 통신을 구현할 수 있습니다.