pile·
백엔드·여기어때 (GC컴퍼니)여기어때 (GC컴퍼니)·

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

여기어때 유저혜택개발팀이 이벤트 쿠폰 API를 Tomcat/JPA 기반 blocking 방식에서 WebFlux/R2DBC 기반 reactive 방식으로 전환하며 수행한 부하 테스트 기록이다. 초기에는 reactive가 4배 빠르다는 결론이 나왔지만, 측정 환경의 교란 요인을 하나씩 제거하자 결론이 완전히 뒤집혔다.

핵심 포인트
  • 부하 생성기와 서버를 같은 머신에서 돌리면 CPU를 공유해 실제 서버 성능이 아니라 머신 전체 한계를 재는 것이다.
  • Redis validateConnection=true 설정 하나가 9.2배의 처리량 차이를 만들었다 — 모든 스레드가 PING 왕복을 기다리며 직렬화됐기 때문이다.
  • INFO 레벨 동기 AOP 로깅은 처리량의 42%를 소비했다.
  • 교란 요인을 제거하고 나니 순수 조회 경로(Redis만 사용, CPU-bound)에서는 blocking(event-api)이 더 빨랐다.
  • I/O-heavy 발급 경로(외부 API 2회+Redis+MySQL+Kafka)에서는 reactive가 약 5배 앞섰다.
  • 전환의 최종 근거는 처리량이 아니라 장애 시 회복력이었다 — 다운스트림 지연 시 스레드 고갈 없이 계속 응답하는 구조.
상세 정리
  • 최초 측정 오류: nGrinder를 arm64 노트북에서 amd64 에뮬레이션으로 실행해 부하 생성기가 1.8배 더 많은 CPU를 썼고, 서버와 생성기가 CPU를 공유해 Vuser를 올려도 TPS가 고정됐다.
  • 1차 수정: 부하 도구를 k6(arm64 네이티브, Go goroutine 기반)로 교체해 생성기 자원 소비를 크게 줄였다.
  • Redis validateConnection=true 함정: LettuceConnectionFactory의 공유 커넥션에서 매 Redis 연산 전 PING 검증이 동기화 블록 안에서 실행돼, 처리량 상한이 PING 왕복 시간의 역수로 묶였다. 설정을 false로 바꾸자 76 → 700 TPS(9.2배) 향상.
  • 로깅 42% 손실: event-api는 매 요청마다 AOP로 요청/응답 본문을 INFO로 기록했다. 동기 Appender라 처리량의 42%를 소비했고, reactive-api는 DEBUG 위주라 영향이 없었다.
  • 조회 경로 최종 비교: 조건을 통일(docker cpus=2, toxiproxy 1ms 주입, validateConnection=false, 로그 OFF) 후 Vuser 1,000 이상에서 blocking이 앞섰다. Redis 단순 조회는 CPU-bound이고 Reactor 파이프라인 오버헤드가 처리량 손실로 이어졌다.
  • 발급 경로 역전: I/O-heavy 경로에서 Vuser 1,000 기준 event-api 약 200 TPS vs reactive-api 약 1,000 TPS(약 5배). 정책 10개 조회를 flatMapSequential로 fan-out해 응답 시간이 순차 합산이 아닌 최대값으로 수렴됐다.
  • 스레드 수 역효과: Tomcat 스레드 1,600은 2코어 환경에서 에러율 15~21%, p99 44초를 만들었고, 200으로 줄이자 에러 0%에 처리량도 동등 이상이었다.
  • 외부 장애 시나리오: Redis 50ms 지연 주입 시 event-api는 동시 처리 건이 스레드 수를 초과해 대기가 쌓였고, reactive-api는 스레드 한계선 자체가 없어 느려지되 죽지 않았다.
  • 최종 결론: 단순 처리량은 워크로드 특성에 따라 갈리며, WebFlux 전환의 정당화 근거는 장애 시 스레드 고갈 없이 계속 응답하는 구조였다.
왜 읽나WebFlux/리액티브 전환을 검토 중인 백엔드 엔지니어, 또는 부하 테스트 결과를 믿기 전 교란 요인을 점검해야 하는 모든 개발자에게 실전 체크리스트를 제공한다.
여기어때 (GC컴퍼니)
여기어때 (GC컴퍼니) 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 백엔드·LINE EngineeringLINE Engineering·

    일본어 상품 검색 정확도 높이기: Elasticsearch + Kuromoji에서 OpenSearch + Sudachi로

    LINE Plus의 통합 커머스 프로젝트에서 일본어 상품 검색 엔진을 Elasticsearch + Kuromoji에서 OpenSearch + Sudachi로 전환한 사례다. 신조어·복합어 미인식과 모델번호 표기 다양성 문제를 해결하기 위해 형태소 분석기를 교체하고 멀티 필드 전략을 설계했다.

    요약 이어보기
    #elasticsearch#opensearch#full-text-search+2
  2. 백엔드·여기어때 (GC컴퍼니)여기어때 (GC컴퍼니)·

    NPE 하나를 팀의 방어 체계로 바꾸기까지

    여기어때 유저혜택개발팀에서 운영 환경 NPE를 원인 추적하다 코드 구조적 결함을 발견하고, 개발자 실수가 아닌 타입과 도메인 설계 수준에서 원천 차단하는 방법으로 전환한 과정을 다룬다. 나아가 Claude Code 기반 AI 에이전트 파이프라인에 장애 교훈을 자동화 체크리스트로 녹이는 방법까지 이어진다.

    요약 이어보기
    #java#null-safety#domain-driven-design+2