웹개발/SpringBoot

Spring WebFlux의 개념과 구조적 특징

bergerac 2025. 5. 29. 09:11

1. Spring WebFlux란?

Spring WebFlux는 Spring 5에서 처음 도입된 비동기 논블로킹(Non-Blocking) 웹 프레임워크다. 전통적인 Spring MVC가 서블릿 기반 동기 처리 모델인 반면, WebFlux는 Reactive Streams 표준에 기반하여 이벤트 기반의 비동기 처리를 지원한다.

이는 대규모 트래픽이 발생하거나, I/O 작업(예: 이메일 발송, 파일 처리, DB 조회 등)이 많은 환경에서 뛰어난 성능을 발휘할 수 있도록 설계되었다.

 

2. 전통적 방식(Spring MVC)의 한계

기존 Spring MVC는 요청당 하나의 쓰레드를 할당하는 방식이다. Tomcat과 같은 서블릿 컨테이너는 내부적으로 스레드 풀을 운영하며, 클라이언트 요청이 들어오면 해당 요청을 처리하기 위해 쓰레드를 점유하게 된다.

[HTTP 요청] -> [Servlet 쓰레드 점유] -> [DB 호출] -> [응답 대기] -> [응답 전송]

이 모델의 문제점은 다음과 같다:

  • 요청 처리 중 I/O 블로킹이 발생하면 쓰레드는 놀고 있음
  • 동시 접속자가 많아지면 스레드 수가 한계에 도달하면서 병목 발생
  • 특히 SMTP, JDBC, 파일 IO 등은 완전히 블로킹 작업이기 때문에 전체 시스템 응답성 저하로 이어질 수 있음

 

3. WebFlux의 구조적 특징

비동기 논블로킹 처리

WebFlux는 모든 요청을 논블로킹 방식으로 처리한다. 이는 쓰레드를 점유하지 않고, 처리할 수 있는 작업만 처리한 뒤 다른 작업을 우선 실행하고, 결과가 도착하면 콜백 방식으로 결과를 이어받는 흐름이다.

  • Mono<T>: 0 또는 1개의 결과를 비동기 처리
  • Flux<T>: 0개 이상의 스트림 형태의 결과를 비동기 처리
Mono<String> mono = Mono.just("hello");
Flux<Integer> flux = Flux.range(1, 5);

 

Schedulers.boundedElastic()

비동기 구조라고 하더라도, 우리가 사용하는 리소스가 완전히 논블로킹이 아닐 수 있다. 예를 들어, JPA, MailSender, 파일 IO는 여전히 블로킹이다. 이런 경우에는 WebFlux에서도 전용 스레드 풀을 활용해야 한다. 이 때 사용하는 것이 Schedulers.boundedElastic()이다.

Mono.fromRunnable(() -> {
    // 블로킹 메일 발송 로직
    mailSender.send(message);
}).subscribeOn(Schedulers.boundedElastic());

4. WebFlux와 JPA의 관계

WebFlux 도입 시 가장 주의할 점 중 하나는 JPA는 블로킹이다라는 사실이다. JpaRepository는 내부적으로 JDBC 기반으로 동작하기 때문에, 아무리 WebFlux를 사용하더라도 DB 요청은 스레드를 점유하게 된다.

따라서 완전한 논블로킹 시스템을 구성하고 싶다면, 반드시 **R2DBC (Reactive Relational Database Connectivity)**를 도입해야 한다.

하지만 현재 Spring Boot에서 MySQL을 사용하는 상황이라면 다음 두 가지 중 하나를 선택해야 한다:

  • JPA를 유지하되, DB 호출은 필요 최소한으로 줄이고 다른 논블로킹 컴포넌트와 조화롭게 사용할 것
  • 또는 JPA를 제거하고, MySQL용 R2DBC 드라이버로 변경할 것

5. WebFlux에서 예외 처리

리액티브 프로그래밍에서는 일반적인 try-catch 대신 onErrorResume 등의 연산자를 활용하여 오류 흐름을 처리한다.

Mono.just("data")
    .map(data -> { throw new RuntimeException("오류 발생"); })
    .onErrorResume(error -> Mono.just("기본값"));

 

6. WebFlux의 실제 흐름(인증 이메일 예시)

[1] 사용자 이메일 입력
   ↓
[2] 인증 요청 수신 (POST /auth/email)
   ↓
[3] Mono 비동기 흐름 시작
   ↓
[4] 인증 코드 생성 + 메일 전송
   ↓
[5] BoundedElastic 스케줄러에서 작업 수행
   ↓
[6] 클라이언트에 응답 (메일 전송 완료)

 

'웹개발 > SpringBoot' 카테고리의 다른 글

Spring Boot + MySQL로 구현한 Student CRUD  (1) 2025.05.30
Email 인증 구현 JavaMailSender 오류 해결  (0) 2025.05.29
JWT(JSON Web Token)  (0) 2025.05.28
Security  (0) 2025.05.27
Rest API  (1) 2025.05.26