#Backend

WebFlux 전환 부하 테스트를 다시 쓴 이야기

WebFlux 전환 부하 테스트를 다시 쓴 이야기
01

Summary

"리액티브 전환으로 4배 향상?" 부하 테스트 보고서를 찢고 처음부터 다시 검증한 진짜 WebFlux 도입기

모래주머니를 찬 블로킹 모델과의 불공정 비교를 바로잡고 깨달은 성능과 장애 회복력의 본질

WebFlux 도입 후 단순 성능 수치에 현혹되지 않고, 철저한 부하 테스트 환경 검증을 통해 숨겨진 병목들을 해결해 나가는 개발 여정입니다. 성능 지표 이면의 자원 경합, 라이브러리 설정, 로깅 정책을 바로잡으며 아키텍처가 제공하는 진정한 가치를 입증합니다.

  • 01노트북 1대 내 자원 경합 및 에뮬레이션 병목을 발견하고 nGrinder에서 Go 기반 k6로 부하 생성기 교체
  • 02Lettuce 커넥션 검증 옵션의 동기식 락이 전체 성능을 9.2배 갉아먹고 있었던 원인 규명 및 해결
  • 03조회성 API 등 가벼운 연산에서는 리액티브 오버헤드로 인해 기존 MVC 모델의 성능이 더 우세할 수 있음을 증명
  • 04다중 외부 API, DB, 메시지 큐가 복합적으로 얽힌 I/O 경로에서 WebFlux가 MVC 대비 약 5배의 압도적 TPS를 달성
  • 05Redis 지연 상황에서 스레드 대기 현상으로 붕괴하는 MVC와 달리 적은 자원으로 장애 상황을 버텨내는 WebFlux의 회복력 확인

RECOMMENDATION

무작정 프레임워크를 바꾸기 전에 기존 시스템의 인프라 설정과 로깅 컨벤션을 먼저 점검하는 것을 권장하며, 고동시성 I/O 집중형 아키텍처나 안정적인 장애 회복력이 필수적인 시스템에 WebFlux 도입을 추천합니다.

The Problem

Spring MVC 기반의 기존 쿠폰 API를 WebFlux로 마이그레이션한 후 초기 부하 테스트에서 4배의 성능 향상을 기록했으나, 이는 로컬 테스트 환경의 자원 경합과 잘못된 설정에서 비롯된 측정 왜곡이었습니다.

The Solution

부하 도구를 가벼운 k6로 교체하고 테스트 환경의 CPU 자원을 물리적으로 격리하였으며, 병목을 유발하던 Lettuce의 커넥션 검증 옵션을 끄고 무거운 로깅을 제거한 후 동등한 조건에서 재테스트를 수행했습니다.

The Result

가벼운 조회 API에서는 Reactor 파이프라인 오버헤드로 인해 MVC가 소폭 우세했으나, 다중 외부 I/O가 얽힌 무거운 발급 API에서는 WebFlux가 약 5배 높은 TPS와 현저히 낮은 꼬리 지연을 보여주었습니다.

Trade-off

CPU 바운드 연산 중심이거나 단순 조회 위주의 경로에서는 리액티브 모델의 컨텍스트 유지 오버헤드로 인해 오히려 MVC보다 성능이 떨어질 수 있으며, 리액티브 스타일 코드의 유지보수 비용이 발생합니다.

03

Key Concepts

Concept · 01

Lettuce Connection Validation

Spring Redis 클라이언트인 Lettuce에서 커넥션 사용 전 유효성을 검증하는 옵션으로, 활성화 시 매번 PING을 전송하며 동기화 블록을 형성합니다.

  • 본문에서는 이 옵션이 켜져 있어 모든 요청 스레드가 네트워크 왕복을 수반하는 동기화 락에 걸려 병목이 발생했습니다.
  • 옵션을 꺼줌으로써 스레드 간 직렬화를 해소하고 왕복 횟수를 절반으로 줄여 9.2배의 TPS 향상을 이끌어냈습니다.
Concept · 02

k6

Go 언어 기반의 가볍고 현대적인 오픈소스 부하 테스트 도구로, 고루틴을 활용해 시스템 리소스를 매우 적게 소모합니다.

  • 로컬의 부족한 CPU 자원 상황에서 arm64 에뮬레이션 비용과 JVM 기반 nGrinder의 무거운 스레드 생성 비용을 극복하기 위해 대안으로 도입되었습니다.
Concept · 03

flatMapSequential

Project Reactor에서 여러 비동기 스트림을 동시에 병렬로 실행하면서도, 방출되는 결과의 순서를 원본 순서대로 정렬해 주는 연산자입니다.

  • 정책 조회 10건을 추가적인 스레드 고갈 없이 완전한 논블로킹 방식으로 병렬화하여, 동기식 순차 조회 대비 응답 속도를 12분의 1로 단축했습니다.