Dev/Testing & Monitoring

성능 테스트 (2) - 시나리오 1

kimyeonjae 2026. 2. 3. 17:48

테스트 방법

K6로 부하를 생성해서, 나오는 결과를 측정합니다. RPS, 응답시간과 에러율 등을 확인힙니다.
또한 Prometheus를 이용하여 CPU 사용률, 메모리, DB 커넥션등 서버 메트릭을 수집힙니다.
위의 정보들을 Grafana로 시각화 하여 확인합니다.

추가적으로 필요시 스레드, 힙, 패킷 덤프 등을 떠서 확인해봅니다.

확인해야 할 것들

RPS(처리량, 초당 요청 수)
- 부하 증가시 RPS가 감소한다면 병목 발생

HTTP 응답시간 P95
- P95가 급격히 올라가면 시스템 포화 상태
- 비효율적인 로직이나 쿼리 개선 필요

활성 HTTP 요청 수
- 계속 증가하면 (처리 속도 < 요청 속도) -> 병목 발생

이외에도 JVM Heap Memory와 GC
DB Connection waiting 등의 메트릭을 확인하였습니다.

사전 작업: Nearby API 성능 장애 해결

현재 서비스에서 좌표 근처 위치 탐색 API (이하 Nearby API)가 간헐적으로 타임아웃(5초 이상 실패) 되며, Grafana에서 스트레스 테스트시, 성공률 1% 미만, P95 응답 시간 60초에 달하는 심각한 성능 장애가 발생했습니다.

{
"api_success_rate": 0.08%,
"http_req_failed": 97.6%,
"query_duration_avg": 39초,
"query_duration_p95": 60초,
"total_queries": 1,149
}

트래픽은 많지만 거의 모든 요청이 실패한 것을 볼 수 있습니다.
특히 해당 API만 DB 커넥션 풀이 고갈되어 타임아웃이 나며, 시스템 전체 과부하 까지 이어지는 것을 확인할 수 있었습니다.

실제 쿼리시간 측정

EXPLAIN ANALYZE을 통해 쿼리 실행 계획과, 실제 소요 시간, 처리 행 수등의 통계를 확인할 수 있습니다.

EXPLAIN ANALYZE
SELECT *
FROM location
WHERE coordinate && ST_MakeEnvelope(...)
AND ST_DWithin(
    coordinate,
    ST_SetSRID(ST_MakePoint(:lon, :lat), 4326),
    :radius
);

결과

Execution Time: 10914 ms (약 11초)
Parallel Seq Scan → GIST 인덱스가 있음에도 전체 테이블을 스캔함 
Rows Removed by Filter: 425040

원인
-> 타입 변환으로 인한 인덱스 미사용

  • GIST 인덱스는 geometry 타입에 생성
  • 쿼리는 geography 타입으로 변환하여 사용됨
  • 타입 변환시 인덱스 사용 x
    기존 Geography를 사용하려 했던 가장 큰 이유로는 Geometry보다 정확한 거리 계산을 위해서였습니다.
    그러나 PostgreSQL은 타입 변환이 포함된 컬럼에 대해 기존 인덱스를 사용할 수 없습니다. 이로 인해 GIST 인덱스가 무시되고 Seq Scan이 선택되어 전체 테이블을 스캔하여 성능 저하가 발생하였습니다.

Geography

  • 구면 좌표계(단위 meter)
  • 정확한 거리 계산
  • 현재 상황에서는 DB 마이그레이션을 통해 인덱스 생성 필요
  • 쿼리 비교적 느림 (계산 비용 높음)

Geometry

  • 평면 좌표계를 사용하고(단위 degree)
  • 쿼리가 비교적 빠름
  • 현재 DB의 GIST 인덱스 사용 가능
  • 극지방 쪽에서는 거리 계산이 부정확 함

해결

  • geometry 타입 유지
  • 타입 변환 제거
    Execution Time: 40.393 ms (0.04초)
    Index Scan using idx_location_coordinate_gist ← 인덱스 사용
    Rows scanned: 56개
    실행시간이 270배 개선되었습니다.

테스트 시나리오 1 - 파일 업로드 테스트

목적 : 무거운 로직인 파일 업로드 성능을 측정해봅니다.

참고

  • 이미지는 테스트용 더미 이미지 파일을 로드합니다 (업로드 요청 한번에 사진 1장 업로드)
  • 업로드 할 때 필요한 인증 로직은 생략합니다
  • 원래 DB에 저장되어있지 않은 로직은 외부 API를 통해 가져오지만, 테스트 데이터(425k개)는 전부 조회된 위치이기에 외부 API 통신 발생 x
  • 우선 대략적인 업로드 시간 확인 및 서비스 초기 정상 작동 확인을 위해 VUser를 최대 20까지 4단계를 거쳐 점진적 증가, 총 테스트 시간은 3분으로 짧게 설정하였습니다
  • 동기식 업로드 입니다

테스트 내용

  • HEIC -> JPG 변환
  • 썸네일 생성
  • EXIF 메타 데이터 추출
실행 시간: 3분 1.7초
총 업로드 횟수: 490회
평균 업로드 시간 : 1,491ms 
P95 업로드 시간 : 2,022ms
P95 HTTP 요청 시간 2,023ms

우선 부하가 크게 걸리지 않은 상황에서 간단히 테스트 한 결과 각 업로드가 평균 1.5초 정도 걸립니다.
현재까지는 충분한 성능을 보여주고 있다 생각합니다. 그러나 VUser 20 수준에서 진행한 테스트 이므로 부하 증가시 성능 저하가 예상됩니다.

추후 서비스가 커지게 되어 성능 개선이 필요하다면

  • 비동기 방식으로 바꾸기
  • 메세지 큐를 활용하여 이미지 변환 작업을 분리해버리기
    정도를 할 수 있습니다.

다음글은 본격적인 테스트를 진행하겠습니다.