Spring MVC와 WebFlux
Spring MVC와 WebFlux
Spring MVC와 WebFlux는 모두 Spring 프레임워크의 웹 애플리케이션 개발을 위한 기술이지만,
동작 방식이 다르며 각각의 장점과 활용 분야가 다릅니다.
이 블로그에서는 Spring MVC와 WebFlux의 특징을 정리하고,
기존의 Spring MVC 기반 프로젝트에서 왜 WebFlux로 전환하게 되었는지에 대한 배경을 설명하고자 합니다.
1. Spring MVC
📌 개념
Spring MVC는 동기(Blocking) 기반의 요청-응답 처리 방식입니다.
Servlet API와 멀티스레드(Thread-per-request) 모델을 사용하여 요청당 하나의 스레드를 할당하는 구조입니다.
📌 특징
- Blocking 방식: 하나의 요청을 처리할 때 해당 스레드는 응답을 반환할 때까지 대기
- 멀티스레드 환경: 요청마다 새로운 스레드를 생성하여 처리
- Servlet 기반
- JDBC, JPA, MyBatis 등과 잘 어울림 (동기적인 데이터베이스 처리 방식)
📌 사용 예시
@RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
User user = userService.getUserById(id);
return ResponseEntity.ok(user);
}
}
- 요청이 오면 UserService를 호출하여 데이터를 가져오고 응답을 반환하는 방식
- 해당 요청을 처리하는 동안 스레드는 응답을 반환할 때까지 대기
📌 장점과 한계
✔️ 익숙한 방식으로 개발이 쉬움
✔️ 동기 방식으로 이해하기 직관적
⚠️ 대량의 동시 요청이 들어오면 스레드가 부족해질 수 있음
⚠️ MongoDB와 같은 NoSQL에서 대량 데이터를 처리할 때 성능 문제가 발생할 수 있음
2. Spring WebFlux
📌 개념
Spring WebFlux는 비동기(Non-Blocking) 기반의 리액티브 프로그래밍을 지원합니다.
Servlet 대신 Netty 또는 Undertow 같은 비동기 웹 서버를 사용하며, 리액티브 스트림(Reactive Streams) 모델을 기반으로 합니다.
📌 특징
- Non-Blocking 방식: 요청 처리를 위한 스레드가 응답을 기다리지 않고 다른 작업을 수행 가능
- 이벤트 루프 기반의 스레드 모델 (Netty 같은 비동기 서버와 함께 사용 가능)
- 리액티브 프로그래밍 지원
- 성능이 중요한 고성능 애플리케이션에서 유리 (예: 실시간 데이터 스트리밍, 대규모 동시 요청 처리)
📌 사용 예시
@RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/users/{id}")
public Mono<User> getUser(@PathVariable Long id) {
return userService.getUserById(id); // Mono<User> 반환 (비동기)
}
}
- Mono<User>를 반환하여 비동기적으로 데이터 응답
- 데이터가 준비될 때까지 스레드는 블로킹되지 않고 다른 요청을 처리 가능
📌 장점과 한계
✔️ 대량의 동시 요청을 효율적으로 처리 가능
✔️ Non-Blocking 방식으로 서버 리소스 활용 최적화
✔️ 대량의 데이터를 스트리밍 방식(Flux)으로 처리하여 메모리 사용 최적화
⚠️ 리액티브 프로그래밍 방식이 익숙하지 않을 경우 학습 비용이 발생
⚠️ 기존 동기 방식(Spring MVC) 코드와의 호환성 고려 필요
3. Spring MVC vs. WebFlux 차이점 정리
구분 | Spring MVC | Spring WebFlux |
기반 기술 | Servlet API | Reactive Streams API |
스레드 모델 | 하나의 요청당 하나의 스레드 (Blocking) | 이벤트 루프 기반 (Non-Blocking) |
주요 서버 | Tomcat, Jetty | Netty, Undertow, Tomcat (Reactive Mode) |
응답 처리 방식 | 동기적 (ResponseEntity<T>) | 비동기적 (Mono<T> 또는 Flux<T>) |
적합한 경우 | 일반적인 웹 애플리케이션 | 높은 동시성을 요구하는 애플리케이션 (예: 실시간 스트리밍, API Gateway 등) |
MongoDB 지원 | 동기 방식으로 호출(성능 저하) | 대용량 데이터 처리, 높은 동시성 요구 환경 |
4. 언제 WebFlux를 선택해야 할까?
WebFlux는 모든 상황에서 필수는 아니며, 아래 경우에 특히 유용합니다.
✔️ 대규모 동시 요청을 처리해야 하는 경우
- 예) 실시간 데이터 스트리밍, WebSocket 기반 애플리케이션
✔️ 비동기 I/O가 많은 경우
- 예) API Gateway, 마이크로서비스 간 통신, WebClient 사용
✔️ 리액티브 프로그래밍을 적용하려는 경우
- 예) Reactor의 Flux와 Mono를 활용한 스트리밍 데이터 처리
✔️ Netty와 같은 비동기 서버를 사용하려는 경우
- 예) 고성능 API 서버 구축
반면, 일반적인 CRUD API 서비스에서는 Spring MVC가 더 익숙하고 직관적이므로 적절한 선택이 될 수 있습니다.
5. 결론
- Spring MVC는 전통적인 동기 방식으로, Servlet API 기반의 간단한 웹 애플리케이션에 적합
- Spring WebFlux는 비동기 Non-Blocking 방식으로, 대량의 동시 요청을 효율적으로 처리할 수 있음
대부분의 일반적인 웹 서비스는 Spring MVC로 충분하지만,
API Gateway, 실시간 데이터 처리, 고성능 애플리케이션에서는 Spring WebFlux가 더 적합합니다.
왜 Spring MVC → WebFlux로 전환했는가?
⚠️ 문제 상황 (MVC 환경에서의 문제)
- MongoDB에서 대용량 데이터를 조회하는 API에서 응답 지연 발생
- 특정 요청이 오래 걸려서 다른 요청들이 대기 상태가 되는 문제 (블로킹)
- CPU 및 스레드 사용률이 급격히 증가하여 서버 리소스 낭비
- 기존 Spring MVC 기반에서는 MongoDB 대량 데이터 조회 시 성능 이슈 발생
- 동기 방식으로 인해 I/O 대기 시간이 길어지고, 응답 시간이 느려짐
✔️ WebFlux 전환 후 개선된 점
- 비동기 데이터 처리로 인해 MongoDB에서 데이터를 효율적으로 가져옴
- 이벤트 루프 방식을 활용하여 동시 요청을 효과적으로 처리
- 서버 부하가 줄어들고 응답 시간이 단축됨
- 대량의 데이터를 스트리밍 방식(Flux)으로 처리하여 메모리 사용 최적화
- 비동기 방식으로 다수의 요청을 효과적으로 처리