| Spring WebFlux | Non-Blocking I/O

아야하면우유·2026년 6월 19일

WebFlux

목록 보기
1/3
post-thumbnail

배경

Spring WebFlux를 배우게 된 이유는 딱히 없습니다. 재밌어 보여서 공부해보려고 합니다. Spring이 제공하는 공식 문서를 읽으며 WebFlux가 무엇인지, 왜 사용되는지에 대해 혼자 공부하기 위해 이 게시글을 열었습니다.
Spring WebFlux 공식 문서


Netty

Netty는 Spring MVC가 WAS로 Apache Tomcat을 채택한 것처럼, Spring WebFlux가 논블로킹 IO를 위해 채택한 서버 프레임워크입니다.

Netty는 처음부터 API 사용과 구현 모두 편리한 경험을 제공한다.

기존의 Spring MVC에서도 현재 Java21 이상의 버전을 이용하여 문제 없이 대용량의, 응답 시간이 긴 데이터를 반환할 수 있게 되었지만 여전히 Backpressure 문제 등이 남아있습니다.
* back pressure : Provider-Consumer Problem에서 Provider가 Consumer의 소비 속도를 뛰어 넘는 문제

Netty의 장점

Netty는 사용 가능한 CPU 코어 수의 두 배 크기를 기본값으로 하는 EventLoopGroup 내에서 스레드 풀을 관리합니다.

EventLoop

이벤트 루프는 특정 이벤트나 메시지가 발생할 때까지 대기하다가 이벤트가 발생하면 디스패치하는 디자인 패턴(혹은 구조체이다.)

  • Event Loop
      무한 반복문을 실행하며 이벤트가 발생할 때까지 대기하다가 이벤트가 발생하면 해당 이벤트를 처리할 수 있는 Handler에게 디스패치한다.
      보통 특정 Channel에 대한 이벤트를 큐에 삽입할 때, 해당 이벤트를 처리할 수 있는 Handler도 같이 첨부해준다.
    • 처음 소켓이 열렸을 땐, accept()하면서 해당 Channel에 AcceptHandler를 첨부해준다.
  • Handler
    이벤트를 받아 비즈니스 로직을 수행한다. (수행완료하고 결과에 맞는 이벤트를 다시 발행하기도한다.)

더 자세한 내용을 참조하려면...

Spring MVC 방식으로 이해하면 DispatcherServlet의 역할으로 이해했습니다.(사견입니다.) MQ가 구현되는 방식도 비슷합니다. 스레드를 잡고 메시지가 도착했는지를 Listening하는 방식이며, Mosquitto의 경우에는 해당 작업을 loop_forever로 논블로킹 I/O를 구현할 수 있습니다.

  다시 돌아와서, Netty는 연결이 설정되고 채널이 생성되면 해당 채널 중 스레드 하나와 연결됩니다. 이 채널에 대해 새 메시지를 수신하거나, 전송할 때마다 동일한 스레드가 사용됩니다.
 Netty를 효율적으로 사용하기 위해서는, 논블로킹 I/O를 수행하는 이벤트 루프 내에서 블로킹 I/O 작업을 수행하면 안 됩니다.(블로킹 작업이 return하기 전까지 논블로킹 작업이 리턴되지 못 하기 때문입니다.) 따라서 I/O 바운드 처리를 위한 별도의 EventLoopGroup을 생성하거나, 표준 Java 유틸리티를 사용하여 작업을 별도의 스레드에서 실행하여야 합니다.

Reactive

반응형이란, 네트워크 I/O, UI 이벤트 등의 변화에 반응하는 프로그래밍 모델이다.

Spring에서는 논블로킹 역압력(back pressure) 처리가 중요합니다. 동기 통신에서는 자연스럽게 역압력 처리가 되지만, 논블로킹 코드에서는 소비자 측의 프로세스가 과부하되지 않도록 생산 속도를 조절해야 할 필요가 있습니다.

예를 들면, Message Queue에서 Publisher와 Subscriber입니다.

Reactive API

반응형 스트림은 라이브러리나, 인프라 구성 요소로는 훌륭하지만 너무 저수준이기 때문에, 애플리케이션 API로는 적절치 않습니다. 비동기 로직을 구현하기 위해서는 고수준의 풍부한 함수형 API가 필요한데, Reactive 라이브러리에 적혀있습니다.

Reactor는 Spring WebFlux에 사용되는 반응형 라이브러리입니다. MonoFlux를 제공하여 데이터 시퀀스를 0~1(Mono)개, 혹은 0~N(Flux)개를 처리할 수 있습니다.

Controller

Spring MVC에서 지원하는 @Controller 어노테이션이거나, 함수형 엔드포인트 두가지 컨트롤러를 선언할 수 있습니다.

  • 어노테이션 : MVC와의 일관성을 유지하지만 동기/비동기 구분이 어렵습니다.
  • 함수형 : 람다 기반의 경량 모델. 어노테이션과 가장 큰 차이는 애플리케이션이 이 어노테이션을 통해 의도를 선언하고, 콜백을 받는 대신 요청 처리를 처음부터 끝까지 직접 담당한다는 점입니다.

Concurrency

MVC는 기본적으로 API 요청을 처리한다는 것이 스레드를 하나 점유한다는 의미였고, 이는 스레드 자체가 블로킹되는 것과 동일하게 보았습니다. 하지만, WebFlux는 항상 요청을 Listening하고 있기 때문에, MVC에 비해서 적은 수의 스레드를 사용합니다.

profile
우유가 넘어지면 아야

0개의 댓글