Java/Spring

[Spring] Spring Webflux

SeungbeomKim 2024. 10. 23. 18:31

오늘은 비동기 기반의 반응형 프로그래밍을 위한 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();
}
  1. Publisher
    • subscribe(): Subscriber를 받아들이는 메서드
  2. Subscriber
    • onSubScribe(): SubScription을 등록하는 메서드
    • onNext(), onError(), onComplete(): Subscription의 신호에 따라 동작하는 메서드
  3. Subscription
    • Publisher와 Subscriber 사이에서 중계하는 역할
    • request(): Subscriber가 Publisher에게 데이터를 요청하는 개수를 의미하는 메서드
    • cancel(): 구독을 취소하는 메서드

 

Reactive Stream Flow

  1. Publisher에 본인이 소유할 Subscription을 구현하고 SubScriber에게 전달한 Data를 생성합니다.
  2. Publisher는 subscribe 메서드를 통해 subscriber를 등록합니다.
  3. SubScriber는 onSubscribe() 메서드를 통해 SubScription을 등록하고, SubScription을 통해 Publisher를 구독합니다. (SubScription을 통해 Publisher, SubScriber 연결)
  4. Subscriber는 Subscription 메서드의 request(), cancel() 메서드를 통해 data의 흐름을 제어합니다.
  5. Subscription의 request()는 조건에 따라 Subscriber의 onNext(), onComplete(), onError()를 호출합니다.
  6. 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 (인증, 인가)를 구축해 보겠습니다.