[ Web Stack] 스프링 부트 Web Stack 종류 - Server MVC & WebFlux

2025. 12. 6. 01:57·ServerDev/SpringBoot

Web Stack 종류

java 언어로 구현하는 백엔드 서버의 프레임워크인 Spring Boot에서 스택을 나눌 수 있다는 것을 알게 되었습니다.
스택을 나누고 구현을 한 적은 없는 것 같은데, 공부해보니 2가지 스택으로 나뉜다고 하더군요.

항목 Servlet 기반 (Spring MVC) WebFlux (Spring WebFlux)
모델 전통적인 동기/블로킹 I/O 비동기/논블로킹 I/O
스레드 모델 요청 1개 = 스레드 1개 요청 N개 ≠ 스레드 N개 (이벤트 루프 기반)
리턴 타입 String, ModelAndView, ResponseEntity Mono<T>, Flux<T>
Servlet API 사용 여부 사용 (예: HttpServletRequest) 사용 안함

공식 문서를 보았는데

정확히 이해는 잘 되진 않지만, Model , Controller , View 등의 층의 계층을 이루고 MySQL 같은 관계형 디비와 연결되어 있는 것을 Servlet 이라 부르는 거 같습니다. 해당 개념을 공부하면서 챗봇 같이 비동기식의 진행이 주인 서비스는 WebFlux로 구성하겠구나 라는 생각이 먼저 들었습니다.

Spring MVC (Servlet)는 Servlet API 기반의 동기(블로킹) 모델이기 떄문에 요청 하나당 보통 하나의 스레드를 점유하며, 그렇기에 요청 처리 중 I/O에서 블로킹이 발생하면 해당 스레드는 대기 상태로 넘어갑니다. Spring WebFlux (Reactive는 Project Reactor 기반의 비동기·논블로킹 모델 으로 이벤트루프/리액티브 스트림으로 많은 동시 연결을 효율적으로 처리합니다. Servlet API에 의존하지는 않지만 Servlet 컨테이너 위에서 제한적으로 실행이 가능합니다.

두개의 차이점을 보자면,
스레드 모델 기준으로

MVC(Servlet): 요청 처리 중 I/O(예: DB, 외부 API)에서 블로킹이 발생하면 해당 스레드는 대기 상태가 되고, 컨테이너는 큰 스레드 풀로 이를 흡수.
WebFlux: 소수의 이벤트루프/논블로킹 스레드로 많은 연결을 처리. 블로킹 호출이 있으면 전체 성능을 해칠 수 있음(블로킹 호출은 별도 스레드로 격리해야 함)

프로그래밍은

MVC: 동기 반환(객체, ResponseEntity) / @Controller, @RestController 방식
WebFlux: Mono, Flux 같은 리액티브 타입 반환이 기본 패턴

 

저는 WebFlux는 써본 적이 없더라구요. 하지만 MVC 내에서 비동기 처리인 sse , ws 를 구현한 적이 있는데 또 SseEmitter는 Servlet 전용 구현이라고 합니다.(즉 Spring MVC 환경에서 사용)

 

WebFlux 환경에서는 Flux 를 이용해서 MediaType.TEXT_EVENT_STREAM_VALUE로 SSE 스트리밍을 제공해야 한다고 함.. 따라서 public SseEmitter ragStream(...) 이면 현재 애플리케이션은 Servlet(MVC) 스택을 쓰고 있음을 의미!

 

그럼 어쨌거나 MVC에서도 비동기 처리가 구현이 된건데 스택을 분리하는게 어떤 의미인지 모르겠더라구요.

 

SSE/WebSocket을 MVC(=Servlet)에서 비동기로 구현했다고 해서 → WebFlux를 사용한 것과 같은 ‘논블로킹 시스템’이 되는 것은 아니다.


MVC에서도 비동기 기술을 쓸 수 있습니다. 하지만 전체 요청 처리 모델 자체는 여전히 동기/블로킹(Servlet 스레드 모델) 입니다.

즉,

WebFlux = 프레임워크 레벨에서 전체가 논블로킹/reactive 설계
Servlet MVC = 일부 API가 비동기 형태일 뿐, 전체 처리 모델은 동기/블로킹

 

그렇다면

왜 MVC에서도 SSE/WS가 가능한데 WebFlux가 따로 있을까?

Servlet MVC의 스레드 모델

Servlet 기반 MVC는 다음 패턴으로 구성되어있습니다.

요청 1개 → Tomcat 스레드 1개를 점유
그 스레드는 Controller, Service, Repository까지 흐르며 블로킹 I/O(DB, 외부 API)에서 대기
스레드가 대기하는 동안 다른 요청을 처리할 수 없음 → 스레드 풀 고갈 가능

SSE / WebSocket ??

SSE(SseEmitter), WebSocket 핸들러는 비동기처럼 “보이지만”
여전히 Tomcat/NIO 스레드가 연결을 유지하며 자원을 점유하고 있기 때문에 DB·API 호출은 여전히 블로킹!

즉, 비동기 기술을 쓰지만 전체 시스템은 Non-Blocking이 아니다.

WebFlux는 요청이 들어와도 스레드를 점유하지 않음 , Reactor + Event Loop 기반으로 I/O 작업도 블로킹되지 않음

실질적으로 CPU 코어 수 수준의 스레드로 수천~수만 연결을 처리 합니다.

SSE/WebSocket은?

WebFlux에서는 SSE나 WebSocket이 진짜 논블로킹으로 스트림 CPU 작업 말고는 거의 스레드를 점유하지 않음.

code example

MVC SSE (SseEmitter)

@GetMapping("/sse")
public SseEmitter sse() {
    SseEmitter emitter = new SseEmitter();

    new Thread(() -> {
        emitter.send("hello");
    }).start();

    return emitter;
}

Controller 입장에서는 요청 처리 스레드를 점유하지 않기에 비동기지만, 내부에서 실행하는 외부 API 호출은 블로킹되어 있습니다. 결국 Tomcat Worker thread는 연결을 계속 유지하는 중임.

WebFlux SSE

@GetMapping(value="/sse", produces=MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> sse() {
    return Flux.interval(Duration.ofSeconds(1))
               .map(i -> "hello " + i);
}

스레드가 연결을 유지하며 블로킹되지 않음.
이벤트 루프 기반으로 스트림을 push하기에 I/O도 Reactive라면 스레드 점유 거의 없음!!

그렇다면 어떤 환경에서 WebFlux로 구성해야 될까?

SseEmitter를 붙인 MVC로도 많은 케이스를 해결할 수 있지만, 다음 조건 중 하나라도 해당하면 풀 WebFlux(End-to-End Reactive) 를 진지하게 고려하는 편이 좋다고 합니다.

동시 연결 수가 매우 많을 때 - 장기 연결(SSE/WebSocket 등)을 수만 건 단위로 유지해야 한다면 WebFlux가 훨씬 자원 효율적이다.

외부 I/O(REST, 원격 DB 등)의 대기 시간이 핵심 병목일 때 - 처리 시간 대부분이 네트워크 대기인 경우 논블로킹 처리로 전체 처리량을 개선할 수 있다.

서비스가 스트리밍/중계(게이트웨이) 역할을 주로 할 때 - 데이터 중계나 backpressure 제어가 필요하면 WebFlux가 자연스럽다.

엔드투엔드 리액티브 도입이 가능한 조직일 때 - Controller → Service → DB까지 리액티브 스택(R2DBC, WebClient 등)으로 바꿀 수 있어야 실효성이 있다.

운영/인프라 비용을 줄이고 싶을 때 - 동일 트래픽에서 스레드·메모리 사용을 줄이면 비용 절감 효과가 발생할 수 있다 (단, 개발·운영 복잡도가 늘어남).

 

지금까지 코 MVC 로의 구성만 봐왔어서 WebFlux 를 실사용하는 곳이 어딘지 찾아봤는데,

https://techblog.woowahan.com/12903/?utm_source=chatgpt.com 

 

[배민스토어] 우리만의 자유로운 WebFlux Practices | 우아한형제들 기술블로그

혹시 배민에서 음식 말고 다른 것들을 주문해 보신 적 있나요? 배민은 각종 전자기기부터 꽃, 화장품, 건강기능식품 등을 배달 받아볼 수 있는 배민스토어 서비스를 운영하고 있습니다. 얼마 전

techblog.woowahan.com

배민스토어는 리뉴얼 과정에서 API 레이어를 모두 WebFlux 기반으로 재작성했다는 블로그 글이 있네요.

특히 “전시 API”처럼 외부 API 호출이 많고 응답 속도가 중요한 엔드포인트들을 WebFlux로 마이그레이션

 



https://tech.hancom.com/webflux-project-reactor-webhwp/?utm_source=chatgpt.com 

 

한컴테크

한컴테크를 통해 한컴의 기술을 공유합니다. 한컴의 프로그래밍, 프레임워크, 라이브러리 및 도구 등 다양한 기술을 만나보세요. 한컴 개발자들의 다양한 지식을 회사라는 울타리를 넘어 여러

tech.hancom.com

한컴테크 에서는 “실시간 협업 + 많은 I/O + 대량 이벤트/스트림 처리” 요구가 있어서,

기존 구조의 병목을 해결하기 위해 WebFlux + Reactor 기반으로 전환했다고 함.

그럼 MVC + SseEmitter로는 언제 충분할까?

트래픽 수준이 보통(장기 연결이 극단적으로 많지 않음)이고,

기존 라이브러리(ORM 등)가 블로킹 기반(JPA 등)일 때,

즉 “지금 당장 성능 문제(스레드 고갈·비용)가 없다면 MVC로도 충분”한 경우가 많다!

'ServerDev > SpringBoot' 카테고리의 다른 글

[JPA] 동시성 제어 : LockModeType.PESSIMISTIC_WRITE  (0) 2025.12.07
[SpringBoot&JPA] QR 코드 기반 게스트 계정 자동 생성 및 로그인 구현  (0) 2025.12.07
[Spring Boot] 권한 검증 - 커스텀 AOP와 Redis로 해결하기 (@IsCouncil)  (0) 2025.12.06
[SpringBoot - SSR] 파일 업로드 에러: "Failed to convert String to MultipartFile" 원인과 해결  (0) 2025.12.06
[Spring Boot] 수정 기능 구현 시, 멀쩡한 데이터가 NULL 로 덮어씌워지는 문제  (0) 2025.12.06
'ServerDev/SpringBoot' 카테고리의 다른 글
  • [SpringBoot&JPA] QR 코드 기반 게스트 계정 자동 생성 및 로그인 구현
  • [Spring Boot] 권한 검증 - 커스텀 AOP와 Redis로 해결하기 (@IsCouncil)
  • [SpringBoot - SSR] 파일 업로드 에러: "Failed to convert String to MultipartFile" 원인과 해결
  • [Spring Boot] 수정 기능 구현 시, 멀쩡한 데이터가 NULL 로 덮어씌워지는 문제
yeseul-kim01
yeseul-kim01
  • yeseul-kim01
    슬 개발일지
    yeseul-kim01
  • 전체
    오늘
    어제
    • 분류 전체보기 (79)
      • 자격증 (1)
        • 정보보안기사 (0)
      • DevOps (17)
        • Docker (6)
        • Kubernetes (1)
        • GitHub Actions (0)
        • AWS (4)
        • Monitoring (1)
        • Nginx (1)
        • GCP (3)
      • ServerDev (34)
        • SpringBoot (13)
        • DJango (5)
        • FastAPI (14)
        • Next (0)
        • Flask (0)
        • Database (2)
      • Algorithm (2)
        • BFS (0)
        • DFS (1)
        • 다익스트라 (0)
      • CS (8)
      • Data Engineering (1)
      • AI&MLOps (2)
      • Architecture (6)
      • Software Engineering (0)
        • Library Packaging (0)
      • Project (5)
        • docx-generator (0)
        • speak-note (2)
        • ms-serving (1)
        • keyshield (2)
      • ProgrammingLanguages (3)
        • Python (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    백엔드
    SpeakNote
    실무일기-백엔드편
    KeyShield
    비동기처리
    di
    하이브리드아키텍처
    Kubernetes
    프로젝트기록-KeyShield
    docker
    실시간시스템
    아키텍처
    동시성제어
    multipartfile
    depends
    실무일기-인프라편
    FastAPI - CORS 마스터
    MLops
    SpringBoot
    STT
    FastAPI
    트러블슈팅
    Django
    NLP부트캠프
    KServe
    아키텍처설계
    grpc
    프로젝트기록-speaknote
    rag
    멀티모듈
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
yeseul-kim01
[ Web Stack] 스프링 부트 Web Stack 종류 - Server MVC & WebFlux
상단으로

티스토리툴바