1. 개요
기존에 운동 일지를 작성할 때 편리함을 주었던 ‘이전 루틴 가져오기’ 기능의 아키텍처적 병목을 해결한 기록입니다. 프론트엔드에서 최근 7~14일 범위의 데이터를 획득하기 위해 날짜 루프를 돌며 병렬로 각각 다중 API 호출을 보내던 방식을, 단 한 번의 요청으로 묶어서 처리해 주는 단일 Batch API 호출 방식으로 세련되게 개선하여 서버 부하와 네트워크 레이턴시를 획기적으로 낮춘 과정을 공유합니다.
2. 핵심 내용
2-1. 기존 루프 병렬 호출 방식의 한계와 네트워크 오버헤드
- 문제 상황: 사용자가 운동 일지 작성 창을 켜고 “이전 루틴 가져오기” 시트를 열 때마다 프론트엔드 단에서 일일이 최근 14일 치의 날짜 배열을 계산하고, 이 배열을 따라 각각 개별 API 요청을 생성해 최대 14번의 중복 요청을 한 번에 날리는 현상이 있었습니다.
- 원인 분석:
- 매번 요청을 보낼 때마다 TCP/TLS 핸드셰이크를 비롯하여 Spring Security 필터 체인(인증/인가 체크), JWT 토큰 파싱 등의 자원 소모적인 작업이 14회씩 독립적으로 반복되었습니다.
- 서버 관점에서도 트래픽이 몰리는 피크 시간대에 다수의 유저가 동시에 해당 시트를 격발할 시, 서버의 톰캣(Tomcat) 스레드 풀과 DB 커넥션 풀을 순식간에 점유하여 시스템 전체의 응답 지연을 초래할 수 있는 심각한 병목 잠재 요인이었습니다.
- 클라이언트 단에서도
Promise.all등으로 비동기 루프를 직접 동기화 제어해야 하는 복잡한 보일러플레이트 코드가 존재하여 유지보수를 어렵게 만들었습니다.
2-2. 백엔드 Batch API 신설 및 단일 호출 전환 (해결책)
이 문제를 근본적으로 타개하기 위해, 기존의 일 단위 개별 조회 방식에서 벗어나 최근 기록 14개를 일괄로 조회할 수 있는 전용 엔드포인트를 마련하는 Hybrid Batch API 방식으로 전환했습니다.
- 스프링 부트(Spring Boot) 백엔드 단:
WorkoutLogRepository에findTop14ByUserUserIdOrderByDateDesc메서드를 간단히 신설하여 DB 레벨에서 단 한 번의 인덱스 정렬 쿼리로 최신 기록 14개를 신속히 긁어오도록 구현했습니다.- 이를 가공하여 한 번에 DTO 리스트로 묶어 리턴해 주는
GET /api/logs/workout/recent엔드포인트를 제공했습니다.
- Next.js 프론트엔드 단:
- 기존 날짜 루프와 비동기
Promise.all로직을 완전히 삭제하고, 새롭게 추가된 단일 엔드포인트fetchRecentWorkoutLogs를 찌르도록 리팩토링했습니다. 이로써 클라이언트의 가독성이 몰라보게 향상되었습니다.
- 기존 날짜 루프와 비동기
2-3. 네트워크 레이턴시 개선 효과 및 추천 라이브러리 검토
단일 API 전환을 통해 네트워크 통신 비용(RTT)은 물론이고 데이터베이스 커넥션 소모 속도가 압도적으로 줄어들었습니다. 특히 모바일 환경처럼 무선 네트워크 감도가 불안정한 곳에서도 여러 번의 핸드셰이크가 생략되면서 사용자가 체감하는 화면 응답 속도가 약 80% 이상 눈에 띄게 개선되었습니다.
- 추천 오픈소스 라이브러리:
k6: 그라파나(Grafana) 진영에서 만든 강력한 모던 Go 기반 부하 테스트 도구입니다. 이처럼 여러 번의 호출을 단일 API로 합쳤을 때, 실제로 시스템 전체 스레드 풀과 커넥션 풀이 얼마나 안정되는지 가상 유저(VU) 시나리오 스크립트(JavaScript/TypeScript)를 작성해 직접 부하를 가하며 손쉽게 벤치마킹할 수 있어 강력히 추천해 드립니다.Spring Boot Actuator&Micrometer: 개발한 엔드포인트의 성능(API 레이턴시, 요청 건수, DB 커넥션 소모 지표)을 실시간 메트릭으로 수집할 수 있는 정석 도구입니다. Prometheus/Grafana와 결합하여 성능 최적화 전후의 변화를 시각적으로 정밀하게 비교 분석할 수 있게 돕습니다.