본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

 

강의 내용

오늘은 project1을 마무리하고 project2인 대용량 트래픽 처리를 위한 접속자 대기열 시스템 프로젝트를 소개하는 강의를 수강했다. 이 프로젝트는 Spring WebFlux와 Redis를 조합하여 동시 접속자를 효율적으로 관리하는 시스템이다. 티켓 예매나 한정 상품 판매처럼 순간적으로 트래픽이 몰리는 상황에서 서버 과부하를 방지하고 공정한 대기 순서를 보장하는 것이 핵심 목표인 것 같다.

 

해당 강의는 webflux와 레디스 위주로 들을 예정이고해당 2가지 내용에 대해  추가적으로 찾아보는 내용들을 주로 작성할 것 같다. Spring WebFlux를 Spring MVC와의 차이점을 살펴보도록 하자.

 

 

Spring MVC: Thread-per-Request 모델의 한계

Spring MVC는 Servlet API 기반으로 동작한다. Tomcat이나 Jetty 같은 서블릿 컨테이너는 기본적으로 200개 정도의 Worker Thread Pool을 유지하며, 각 HTTP 요청이 들어오면 풀에서 스레드 하나를 할당받아 처리한다.

 

문제는 I/O 작업이 발생할 때다. 데이터베이스 쿼리를 실행하거나 외부 API를 호출하면 해당 스레드는 응답을 받을 때까지 블로킹된다. 예를 들어 평균 응답 시간이 500ms인 외부 API를 호출한다면, 그 시간 동안 스레드는 아무 일도 하지 못하고 대기만 한다. Thread Pool 크기가 200이라면 초당 최대 400개의 요청만 처리할 수 있다는 계산이 나온다.

 

Spring MVC에서도 @Async, Callable, DeferredResult를 사용해 비동기 처리가 가능하다. 하지만 이는 서블릿 컨테이너 스레드와 비즈니스 로직 처리 스레드를 분리하는 것일 뿐, 최종적으로는 서블릿 스레드로 다시 돌아와 InputStream/OutputStream으로 블로킹 I/O를 수행해야 한다. 즉, end-to-end 논블로킹이 아니다.

 

Spring WebFlux: Event Loop와 Non-blocking I/O

 

Spring WebFlux는 Netty를 기본 서버로 사용한다. Netty는 이벤트 루프 기반으로 동작하는데, 일반적으로 CPU 코어 수만큼의 Event Loop Thread를 생성한다. 8코어 서버라면 8개의 스레드로 수천 개의 동시 연결을 처리할 수 있다.

이것이 가능한 이유는 Non-blocking I/O 때문이다. 소켓에서 데이터를 읽을 때 read() 호출이 즉시 리턴되며, 데이터가 준비되면 OS가 이벤트를 발생시킨다. Event Loop Thread는 이 이벤트를 감지하고 등록된 콜백을 실행한다. I/O 대기 중에도 스레드는 다른 이벤트를 계속 처리할 수 있다.

 

성능 특성: 처리량 vs 응답 시간

Baeldung의 벤치마크에 따르면, Spring MVC와 WebFlux의 단일 요청 응답 시간은 큰 차이가 없다. 오히려 리액티브 오버헤드로 인해 WebFlux가 약간 느릴 수 있다.

차이가 나타나는 것은 높은 동시성 상황이다. 동시 요청 1000개를 처리할 때 Spring MVC는 Thread Pool 고갈로 응답 시간이 급격히 증가하지만, WebFlux는 일정한 응답 시간을 유지한다. 메모리 사용량도 MVC는 스레드 스택 메모리(각 1MB)로 인해 선형적으로 증가하지만, WebFlux는 스레드 수가 고정되어 있어 거의 일정하다.

단, 전체 스택이 논블로킹이어야 이런 이점이 있다. JPA나 JDBC처럼 블로킹 API를 WebFlux에서 사용하면 Event Loop Thread가 블로킹되어 오히려 성능이 떨어진다. 이 경우 R2DBC 같은 리액티브 데이터베이스 드라이버를 사용해야 한다.

 

WebFlux 적용 기준

 

Spring 공식 문서는 명확한 가이드를 제시한다. 이미 잘 작동하는 Spring MVC 애플리케이션이 있다면 바꿀 필요가 없다. 대부분의 비즈니스 애플리케이션에서 MVC의 성능으로 충분하며, 명령형 프로그래밍이 디버깅과 유지보수에 유리하다. WebFlux를 선택해야 하는 경우는 다음과 같다.

 

첫째, 외부 API 호출이 많고 레이턴시가 긴 마이크로서비스 아키텍처.

둘째, 스트리밍 데이터나 Server-Sent Events처럼 장시간 연결이 필요한 경우.

셋째, 적은 리소스로 높은 동시 연결을 처리해야 하는 경우다.

다만 리액티브 프로그래밍의 학습 곡선이 가파르다는 점을 고려해야 한다. 팀 전체가 함수형 프로그래밍과 비동기 처리에 익숙해져야 하며, 디버깅도 까다롭다. 성능 이점이 명확한 상황이 아니라면 MVC로 시작하고, 필요할 때 WebClient 같은 리액티브 컴포넌트를 부분적으로 도입하는 것이 현실적인 접근이다.

 

 

참고 출처

 

 

시작 시간
종료 시간
학습 인증
수강 인증

 

 

 

https://fastcampus.info/4oKQD6b

+ Recent posts