오늘은 비동기 기반의 반응형 프로그래밍을 위한 Framework인 Webflux에 대해 알아보려고 합니다. Webflux를 사용하기 위해서는 Reactive Stream, Mono, Flux, r2dbc 등 다양한 개념을 인지하고 있어야 하는데, 이러한 개념들을 대략적으로 정리해 보도록 하겠습니다.
WebFlux에 근간이 되는 Reactive Programming 방식에 대해서 설명드린 후, WebFlux에 대해 알아보도록 하겠습니다.
Reactive Programming (반응형 프로그래밍)
- 데이터의 흐름과 변경사항의 전파에 중점을 둔 선언적 프로그래밍 패러다임
- 패더라임: 어떤 한 시대의 사람들의 견해나 사고를 근본적으로 규정하고 있는 테두리로서의 인식의 체계, 또는 사물에 대한 이론적인 틀이나 체계를 의미하는 개념
- 선언적 프로그래밍: 무엇을 해야할지 따로 표현을 만들어 기술하고, 언제 어떻게 동작하는지 내부 소스코드에서 처리해 주는 방식의 프로그래밍
- ex) 스프레드시트 (A1+B1 → 변경사항이 전파되어 C1에 값이 변경)
Spring Boot Webflux
- 반응형, 비동기적인 웹 애플리케이션 개발을 지원하는 프레임워크
- 명령형 프로그래밍을 활용하고 동기 방식의 Spring Mvc와는 대비됩니다.
- Reactive Stream 표준을 기반으로 비동기 데이터 흐름을 처리하고, 대규모 트래픽이나 성능이 중요한 애플리케이션을 구축할 수 있습니다.
앞서 설명드렸듯이, WebFlux는 Reactive Stream 표준을 기반으로 하는 프레임워크입니다. Reactive Stream의 Component와 Flow에 대해 설명드리겠습니다.
Reactive Stream
- non-blocking backPressure을 이용하여 비동기 스트림 처리의 표준을 제공합니다.
- 비동기의 경계를 명확히하여 스트림 데이터의 교환을 효과적으로 관리하는 것이 주된 목적입니다.
- backPressure: 비동기 스트림 처리에서 “데이터의 양을 제어” 하는 역할을 담당합니다.
Reactive Stream API Component
public interface Publisher<T> {
public void subscribe(Subscriber<? super T> s);
}
public interface Subscriber<T> {
public void onSubscribe(Subscription s);
public void onNext(T t);
public void onError(Throwable t);
public void onComplete();
}
public interface Subscription {
public void request(long n);
public void cancel();
}
- Publisher
- subscribe(): Subscriber를 받아들이는 메서드
- Subscriber
- onSubScribe(): SubScription을 등록하는 메서드
- onNext(), onError(), onComplete(): Subscription의 신호에 따라 동작하는 메서드
- Subscription
- Publisher와 Subscriber 사이에서 중계하는 역할
- request(): Subscriber가 Publisher에게 데이터를 요청하는 개수를 의미하는 메서드
- cancel(): 구독을 취소하는 메서드
Reactive Stream Flow
- Publisher에 본인이 소유할 Subscription을 구현하고 SubScriber에게 전달한 Data를 생성합니다.
- Publisher는 subscribe 메서드를 통해 subscriber를 등록합니다.
- SubScriber는 onSubscribe() 메서드를 통해 SubScription을 등록하고, SubScription을 통해 Publisher를 구독합니다. (SubScription을 통해 Publisher, SubScriber 연결)
- Subscriber는 Subscription 메서드의 request(), cancel() 메서드를 통해 data의 흐름을 제어합니다.
- Subscription의 request()는 조건에 따라 Subscriber의 onNext(), onComplete(), onError()를 호출합니다.
- Subscriber의 해당 메서드의 로직에 따라 request(), cancel()로 응답합니다.
WebFlux에서 사용되는 Reactive Stream의 개념, 관련 컴포넌트, 동작과정에 대해 알아보았으니, JVM에서 동작하는 non-blocking reactive Library인 reactor와 핵심 구성요소인 Mono, Flux에 대해 설명드리겠습니다.
Reactor
- Pub-Sub Pattern을 중심으로 동작하고 데이터를 Pub에서 생성 및 가공하고, Sub로 전달해 주는 역할을 담당합니다.
- Mono, Flux라는 두 가지 API를 제공하여 비동기 데이터 흐름을 제어합니다.
Mono
- Reactor Library에서 제공하는 Publisher 중 하나로 한 개의 데이터 항목을 생성하는 객체
- Mono를 사용하여 비동기적으로 결과를 반환하면, 해당 결과를 구독하는 클라이언트는 결과가 생성되기까지, 블로킹하지 않고 다른 작업을 수행할 수 있습니다.
Flux
- Reactor Library에서 제공하는 Publisher 중 하나로 여러 개의 데이터 항목을 생성하는 객체
- Mono와 마찬가지로 결과가 생성되기까지 다른 작업을 수행할 수 있습니다.
일반적으로 JPA, JDBC와 같은 DB 접근 기술을 사용할때는 MariaDB, Mysql을 사용하는데요. Reactive Programming에서도 이들을 사용하기 위해서는 r2dbc를 활용해야 합니다.
r2dbc (reactive relational database connectivity)
- RDB에서 reactive programming을 가능하게 해주는 DB 접근 API
- Spring WebFlux와 같은 reactive programming 환경에서 DB와의 통신을 비동기적으로 처리하는데 적합합니다.
WebFlux에 대해서도 알아보았으니, Spring Mvc와 이를 비교해서 설명드리도록 하겠습니다.
Spring Mvc vs Spring WebFlux
Blocking Request vs Non-Blocking Request
- Blocking Request: Spring Mvc, Client Request에 Response를 반환하기 전까지 대기합니다.
- Non-Blocking Request: Spring Webflux, Client Request에 Response를 반환하기 전까지 다른 작업 수행이 가능합니다.
Controller vs Router
- Controller
- Spring Mvc, Rest API Endpoint를 통해 HTTP 요청을 동기적으로 처리를 담당하는 컴포넌트
- Annotation을 사용하면 URL 경로를 지정합니다.
- @RequestMapping annotation을 사용하여 요청을 매핑합니다.
- @RestController annotation을 사용하여 요청에 대해 응답합니다.
- @ControllerAdvice를 통해 예외 처리 핸들러를 등록합니다.
- Router
- Spring WebFlux, 비동기적으로 실행되며 스레드가 블로킹되지 않아 더 높은 처리량을 달성할 수 있는 컴포넌트
- Java DSL을 사용하여 라우팅 규칙을 정의합니다.
- RequestPredicate를 사용하여 요청을 매핑합니다.
- SeverResponse or HandlerFunction 타입의 객체를 반환합니다.
- RouterFunction에서 예외처리를 담당합니다.
- RequestPredicates
- Spring WebFlux에서 HTTP 요청을 처리하기 위한 RouterFunction을 작성할 때 사용되는 요청 매핑 조건을 나타내는 클래스
- HandlerFunction
- 단일 입력과 단일 출력을 가지며 Spring WebFlux가 HTTP 요청을 처리하기 위해 호출되는 메서드
- RouterFunction
- Handler Function을 호출하는 역할을 담당합니다. HTTP 요청을 받고 적절한 Handler Function으로 라우팅하는 역할
RestTemplate vs WebClient
- RestTemplate
- HTTP 통신에서 유용하게 쓸수 있는 템플릿
- Rest 서비스를 호출하도록 설계되어 HTTP 프로토콜 메서드(crud) 제공합니다.
- 통신을 단순화하고 Restful 원칙을 지킵니다.
- 멀티쓰레드 방식을 사용합니다.
- Blocking 방식을 사용합니다.
- dependency
- implementation 'org.springframework.boot:spring-boot-starter-web
- WebClient
- 비동기 클라이언트 방식
- 싱글스레드 방식을 사용합니다.
- Non-blocking 방식을 사용합니다.
- dependency
- implementation 'org.springframework.boot:spring-boot-starter-webflux
Spring Mvc는 blocking, multi-thread 기반으로 동작하고, Spring Webflux는 non-blocking, single-thread 방식으로 동작하는 것을 확인할 수 있습니다. 또한 HTTP 통신에서 Spring Mvc는 Controller, Resttemplate을 활용하지만, Spring Webflux에서는 Router, WebClient를 활용하는 것을 알 수 있습니다.
Spring WebFlux에 대해 정리해 보았는데 학습곡선이 매우 넓은 것 같습니다. 이제 위 개념들을 잘 숙지해서 Webflux 기반의 Auth-Server (인증, 인가)를 구축해 보겠습니다.