GameLog의 주요 기능 구현을 어느 정도 마무리한 뒤, 실제 서비스처럼 데이터가 많아졌을 때도 API가 정상적으로 동작하는지 확인해보기로 했다.
특히 GameLog는 IGDB에서 게임 데이터를 가져와 검색과 추천 기능에 활용하고 있기 때문에, 데이터가 수십만 건까지 증가했을 때 조회 및 추천 API의 성능이 어떻게 변하는지 확인하는 것이 필요했다.
이를 위해 대량의 게임 데이터를 구축하고, 테스트 코드를 보완하는 동시에 k6, Prometheus, Grafana를 활용한 성능 테스트 및 모니터링 환경을 구성했다.
1. IGDB 대용량 데이터 구축
개발 과정에서는 비교적 적은 양의 데이터로 API를 테스트했기 때문에, 실제 서비스에서 게임 데이터가 수십만 건까지 증가했을 때 현재의 쿼리가 충분히 빠르게 동작할지는 확인하기 어려웠다.
그래서 IGDB 데이터를 대량으로 저장해 실제 데이터 규모에 가까운 환경에서 성능을 측정하기로 했다.
기존 DB와 분리
기존 개발 DB에는 사용자와 리뷰 등 테스트에 필요한 데이터가 이미 존재했기 때문에, 대용량 게임 데이터를 별도의 Docker DB/볼륨에 구축했다.
최신 Entity 구조를 기준으로 빈 테이블을 먼저 생성한 뒤, 준비한 SQL dump를 주입하는 방식으로 데이터를 구성했다.
대상 테이블은 다음과 같다.
- games
- genres
- platforms
- game_series
- 게임-장르, 게임-플랫폼 등 연관 테이블
약 30만~38만 건 수준의 게임 데이터를 구축해 대량 데이터 환경을 만들었다.
2. 서비스 테스트 보강
대량 데이터 성능 테스트와 함께 기존 테스트 코드도 다시 점검했다.
단순히 테스트 개수를 늘리는 것보다 실제 서비스 로직에서 문제가 발생할 수 있는 경계 조건과 예외 상황을 검증하는 것에 초점을 맞췄다.
특히 UserGame 관련 로직을 중심으로 다음과 같은 상황을 추가로 확인했다.
- 게임 기록 생성
- 기존 게임 기록 수정
- 플레이 상태 변경
- 잘못된 요청
- 존재하지 않는 데이터
- 경계값
정상적인 요청뿐만 아니라 예외 상황에서도 서비스가 의도한 대로 동작하는지 확인할 수 있도록 테스트 범위를 넓혔다.
3. Actuator Endpoint 테스트
Prometheus를 이용해 서버의 metric을 수집하기 위해 Spring Boot Actuator endpoint도 테스트 대상으로 추가했다.
MonitoringControllerTest를 통해 다음 endpoint가 정상적으로 동작하는지 확인했다.
/actuator/health
서버의 상태를 확인하는 endpoint가 정상적으로 응답하는지 테스트했다.
- HTTP Status 200
- 응답 상태 UP
/actuator/prometheus
Prometheus가 수집할 수 있는 metric이 정상적으로 노출되는지도 확인했다.
- HTTP Status 200
- # HELP
- # TYPE
등 Prometheus metric 형식이 포함되어 있는지 검증했다.
기존에 구성해둔 test용 application 설정을 활용해 테스트 환경에서 Actuator endpoint를 독립적으로 검증했다.
4. Prometheus + Grafana 모니터링 구축
기능 테스트만으로는 실제 서버의 요청량이나 응답 시간, 리소스 사용량을 확인하기 어렵다.
그래서 Prometheus + Grafana 기반 모니터링 환경을 추가했다.
각 도구의 역할은 다음과 같이 구분했다.
| 도구 | 역할 |
| JUnit / Spring Boot Test | 기능 및 API 테스트 |
| Prometheus | 서버 metric 수집 |
| Grafana | metric 시각화 및 성능 분석 |
| k6 | 부하 테스트 |
Spring Boot에서 제공하는 metric을 Prometheus가 수집하고, Grafana에서 이를 시각화하는 구조로 구성했다.
Grafana Dashboard 구성
성능 테스트에서 확인하고 싶은 지표를 기준으로 Grafana Dashboard를 구성했다.
1. Request Rate
sum(rate(http_server_requests_seconds_count[1m]))
→ 최근 1분 동안 초당 처리된 HTTP 요청 수를 확인한다.
요청량이 증가했을 때 서버가 얼마나 많은 요청을 처리하고 있는지 확인하기 위한 지표다.
2. JVM Memory
jvm_memory_used_bytes
→ JVM에서 사용 중인 메모리 사용량을 확인한다.
부하가 증가하면서 메모리 사용량이 급격하게 증가하거나 지속적으로 누적되는지 확인할 수 있다.
3. CPU Usage
process_cpu_usage
→ 애플리케이션 프로세스의 CPU 사용률을 확인한다.
부하 테스트 과정에서 CPU가 병목으로 작용하고 있는지 확인하기 위해 사용했다.
4. Virtual Users
k6_vus
→ k6에서 현재 실행 중인 가상 사용자(Virtual Users) 수를 확인한다.
현재 얼마나 많은 가상 사용자가 동시에 테스트를 수행하고 있는지 확인하기 위한 지표다.
5. P99 Response Time
k6_http_req_duration_p99
→ API 요청 응답시간의 P99를 확인한다.
전체 요청 중 약 99%가 어느 정도의 응답시간 안에 처리되는지를 확인할 수 있어, 평균 응답시간만으로는 확인하기 어려운 느린 요청의 성능을 파악하는 데 활용했다.
6. Error Rate
avg(k6_http_req_failed_rate)
→ 전체 요청 중 실패한 요청의 비율을 확인한다.
부하가 증가했을 때 API 오류율이 증가하는지 확인하기 위해 사용했다.
5. k6를 이용한 부하 테스트
모니터링 환경을 구축한 뒤 실제 API에 부하를 발생시키기 위해 k6를 이용한 부하 테스트를 구성했다.
k6 run k6/usergame-test.js
테스트 대상에는 다음과 같은 주요 API를 포함했다.
- Library 목록 조회
- Profile 조회
- 주요 게임 관련 API
Docker Compose 환경에서는 모니터링 도구를 별도로 구성했다.
- MySQL → 기존 Docker Compose
- Prometheus → localhost:9090
- Grafana → localhost:3001
k6에서 가상 사용자를 증가시키면서 요청을 발생시키고, Prometheus가 서버 metric을 수집하도록 구성했다.
이후 Grafana에서 Request Rate, P99 Response Time, CPU Usage, JVM Memory, Error Rate 등을 함께 확인하면서 부하에 따른 서버의 변화를 확인할 수 있도록 했다.
6. Spring 로그 기준 정리
성능 테스트와 모니터링을 진행하면서 게임 기록과 프로필 탭에서 주요 동작을 추적할 수 있도록 Spring 로그를 추가했다.
모든 요청에 로그를 남기기보다는 로그 레벨에 따라 역할을 나누어 필요한 정보만 기록하도록 했다.
DEBUG
조회성 작업은 DEBUG 로그로 기록했다.
공개 프로필에서 게임 목록을 조회하는 경우에도 대상 사용자와 페이징 정보를 기록했다.
공개 프로필 게임 목록 조회 - targetUserId={}, page={}, size={}
INFO
게임 기록 생성이나 상태 변경처럼 실제 데이터에 변화가 발생하는 작업은 INFO 로그로 기록했다.
게임 기록 저장 및 수정:
게임 기록 저장 요청 - userId={}, gameId={}
게임 기록 수정 완료 - userId={}, gameId={}
게임 라이브러리 등록 완료 - userId={}, gameId={}
플레이 상태 및 각 게임 상태 변경:
플레이 상태 변경 - userId={}, gameId={}, playStatus={}
플레이 상태 해제 - userId={}, gameId={}
플레이 중 상태 변경 - userId={}, gameId={}, playing={}
위시리스트 상태 변경 - userId={}, gameId={}, wishlist={}
백로그 상태 변경 - userId={}, gameId={}, backlog={}
좋아요 상태 변경 - userId={}, gameId={}, liked={}
WARN
정상적인 상태 변경이 아닌 예상하지 못한 요청이나 잘못된 상태의 변경 요청은 WARN으로 기록했다.
예를 들어 라이브러리에 등록되지 않은 게임의 상태를 해제하려는 경우 다음과 같이 기록한다.
라이브러리에 등록되지 않은 게임의 상태 해제 요청 - userId={}, gameId={}
이처럼 일반적인 400/404 응답마다 개별 로그를 추가하기보다는, 실제로 원인 파악이 필요한 상황에만 WARN 로그를 남겨 불필요한 중복 로그를 줄였다.
ERROR
예외는 각 Service에서 개별적으로 처리하기보다 GlobalExceptionHandler에서 중앙 처리하도록 했다.
이를 통해 동일한 예외가 여러 계층에서 중복으로 기록되는 것을 방지하고, 예외 로그를 한 곳에서 일관되게 관리할 수 있도록 했다.
또한 로그에는 JWT/token이나 개인정보와 같은 민감한 정보가 포함되지 않도록 주의했다.
7. 테스트와 모니터링의 역할 분리
이번 작업을 진행하면서 각각의 도구가 담당하는 역할을 명확하게 구분할 수 있었다.
기능 검증
JUnit / Spring Boot Test
→ API와 서비스 로직이 올바르게 동작하는지 검증
부하 발생
k6
→ 실제 API에 가상 사용자를 이용해 부하를 발생시킴
metric 수집
Prometheus
→ 서버와 k6에서 발생하는 metric 수집
시각화 및 분석
Grafana
→ 수집된 데이터를 Dashboard로 시각화하고 성능 상태를 분석
기능이 정상적으로 동작하는지 확인하는 것에서 끝나는 것이 아니라, 실제 부하 상황에서 서버가 어떻게 동작하는지 관찰할 수 있는 환경까지 구성했다.
마무리
이번 작업에서는 GameLog의 기능을 추가하는 것보다 이미 구현한 기능이 실제 데이터 규모와 부하에서도 어떻게 동작하는지 확인하기 위한 기반을 마련하는 것에 집중했다.
약 30만~38만 건의 IGDB 데이터를 구축해 대량 데이터 환경을 만들었고, 기존 서비스 테스트에 경계값과 예외 상황을 추가했다.
또한 k6를 이용해 실제 API에 부하를 발생시키고, Prometheus와 Grafana를 연결해 요청량, 응답시간, CPU, JVM Memory, 가상 사용자 수, 오류율을 하나의 Dashboard에서 확인할 수 있도록 구성했다.
특히 단순히 테스트를 실행하는 것에서 끝나는 것이 아니라, 부하 → metric 수집 → 시각화 → 성능 분석으로 이어지는 환경을 직접 구성하면서 성능 테스트와 모니터링이 어떻게 연결되는지 경험할 수 있었다.
다음 단계에서는 대용량 데이터 환경에서 실제 추천 쿼리의 병목을 분석하고, 쿼리 최적화를 통해 개선 전후의 성능을 비교해볼 예정이다.
'회고 > GameLog 프로젝트' 카테고리의 다른 글
| 2차 프로젝트: GameLog - 발표 대본 작성과 시연 리허설 (0) | 2026.09.30 |
|---|---|
| 2차 프로젝트: GameLog - 발표자료 정리와 프로젝트 마무리 (0) | 2026.09.29 |
| 2차 프로젝트: GameLog - 전체 기능 점검 (0) | 2026.09.23 |
| 2차 프로젝트: GameLog - 프로필 기능 개선 (0) | 2026.09.23 |
| 2차 프로젝트: GameLog - 프로필 탭 API 구현 (0) | 2026.09.21 |
댓글