부하테스트 시나리오 5: 채널 목록 조회 - 100-hours-a-week/2-hertz-wiki GitHub Wiki

1. 사용자 시나리오 설명

시나리오 설명: 사용자가 개인 채널보관함 목록을 조회

로그인한 사용자가 개인 채널보관함 페이지에 접속하여, 본인이 참여 중인 채널 목록을 최근 메시지 기준으로 조회합니다. 해당 목록은 페이지네이션되어 있으며, API는 /api/v1/channel?page={페이지번호}&size={페이지크기}입니다. 서버는 DB에서 해당 유저의 채널 목록과 메시지 메타데이터를 응답합니다.

2. 테스트 개요

항목 내용
테스트 목적 사용자 보관함 진입 시 채널 목록 조회 성능 및 부하 검증
테스트 환경 - Monolithic: e2-custom-2-6144 (vCPU 2개, 메모리 6GB)
대상 시스템 백엔드(Spring Boot + MySQL)
테스트 도구 k6
테스트 일시 2025년 5월 27일

2.1 테스트 목적

사용자가 자신의 채널보관함 목록을 확인하는 과정에서 발생하는 부하에 대해, 시스템이 얼마나 안정적으로 응답할 수 있는지 검증합니다. 이는 채널 접속 전 사용자 홈 진입 단계에서 발생하는 트래픽이며, 5초 간격으로 반복 호출되는 API입니다.(Polling)

2.2 테스트 API 및 호출 흐름

어플리케이션 API 엔드포인트 메서드 설명
Spring Boot /api/v1/channel?page={페이지번호}&size={페이지크기} GET 사용자 채널보관함 목록 반환 API (Authorization 필요)

3. 테스트 조건 및 부하 프로파일

차수 1차 2차 3차 4차
동시 사용자 수 50명 100명 400명 500명
총 요청 시간 30초 30초 30초 30초
요청 간격 3초 3초 3초 3초
부하 생성 패턴 shared-iterations (고정 요청 수 분배) shared-iterations shared-iterations shared-iterations
배치 처리 방식 멀티스레드 기반 동시 요청 처리 멀티스레드 기반 동시 요청 처리 멀티스레드 기반 동시 요청 처리 멀티스레드 기반 동시 요청 처리

4. 테스트 결과 요약

🔹 1차 테스트 결과

K6

항목 정의
최대 VU 수 (vus_max) 50 동시에 실행된 최대 가상 사용자 수 (Virtual Users)
총 요청 수 (http_reqs) 300 전체 테스트 동안 실행된 HTTP 요청 수
평균 응답 시간 (avg) 137.83ms 전체 요청의 평균 응답 시간
최대 응답 시간 (max) 648.29ms 가장 느린 요청의 응답 시간
90% 응답 시간 (p90) 400.11ms 90%의 요청이 이 시간 이하로 응답됨
95% 응답 시간 (p95) 508.05ms 95%의 요청이 이 시간 이하로 응답됨
에러율 (http_req_failed) 0.00% 실패한 HTTP 요청의 비율
성공률 (checks_succeeded) 100.00% 성공 조건을 만족한 요청 비율 (예: 응답 코드 200, JSON 형식 등)
요청 완료 시간 (iteration_duration.avg) 5.17s 1회 요청당 평균 전체 실행 시간
총 테스트 시간 약 31.4초 전체 부하 테스트가 완료되기까지 걸린 시간

전체 리소스 사용량

image

image 1

어플리케이션별 리소스 사용량

image 2

image 3

APM 결과(API 지연 시간, 호출 수, 에러율)

image 4

🔹 2차 테스트 결과

K6

항목 정의
최대 VU 수 (vus_max) 100 동시에 실행된 최대 가상 사용자 수 (Virtual Users)
총 요청 수 (http_reqs) 600 전체 테스트 동안 실행된 HTTP 요청 수
평균 응답 시간 (avg) 202.07ms 전체 요청의 평균 응답 시간
최대 응답 시간 (max) 1.17s 가장 느린 요청의 응답 시간
90% 응답 시간 (p90) 604.86ms 90%의 요청이 이 시간 이하로 응답됨
95% 응답 시간 (p95) 956.15ms 95%의 요청이 이 시간 이하로 응답됨
에러율 (http_req_failed) 0.00% 실패한 HTTP 요청의 비율
성공률 (checks_succeeded) 100.00% 성공 조건을 만족한 요청 비율 (예: 응답 코드 200, JSON 형식 등)
요청 완료 시간 (iteration_duration.avg) 5.21s 1회 요청당 평균 전체 실행 시간
총 테스트 시간 약 31.9초 전체 부하 테스트가 완료되기까지 걸린 시간

전체 리소스 사용량

image 5

image 6

어플리케이션별 리소스 사용량

image 7

image 8

APM 결과(API 지연 시간, 호출 수, 에러율)

image 9

🔹 3차 테스트 결과

K6

항목 정의
최대 VU 수 (vus_max) 400 동시에 실행된 최대 가상 사용자 수 (Virtual Users)
총 요청 수 (http_reqs) 2336 전체 테스트 동안 실행된 HTTP 요청 수
평균 응답 시간 (avg) 520.27ms 전체 요청의 평균 응답 시간
최대 응답 시간 (max) 4.48s 가장 느린 요청의 응답 시간
90% 응답 시간 (p90) 2.19s 90%의 요청이 이 시간 이하로 응답됨
95% 응답 시간 (p95) 3.31s 95%의 요청이 이 시간 이하로 응답됨
에러율 (http_req_failed) 0.00% 실패한 HTTP 요청의 비율
성공률 (checks_succeeded) 100.00% 성공 조건을 만족한 요청 비율 (예: 응답 코드 200, JSON 형식 등)
요청 완료 시간 (iteration_duration.avg) 5.59s 1회 요청당 평균 전체 실행 시간
총 테스트 시간 약 35초 전체 부하 테스트가 완료되기까지 걸린 시간

전체 리소스 사용량

image 10

image 11

어플리케이션별 리소스 사용량

image 12

image 13

APM 결과(API 지연 시간, 호출 수, 에러율)

image 14

image 15

🔹 4차 테스트 결과

K6

항목 정의
최대 VU 수 (vus_max) 500 동시에 실행된 최대 가상 사용자 수 (Virtual Users)
총 요청 수 (http_reqs) 2399 전체 테스트 동안 실행된 HTTP 요청 수
평균 응답 시간 (avg) 693.31ms 전체 요청의 평균 응답 시간
최대 응답 시간 (max) 4.84s 가장 느린 요청의 응답 시간
90% 응답 시간 (p90) 2.71s 90%의 요청이 이 시간 이하로 응답됨
95% 응답 시간 (p95) 3.81s 95%의 요청이 이 시간 이하로 응답됨
에러율 (http_req_failed) 0.00% 실패한 HTTP 요청의 비율
성공률 (checks_succeeded) 100.00% 성공 조건을 만족한 요청 비율 (예: 응답 코드 200, JSON 형식 등)
요청 완료 시간 (iteration_duration.avg) 5.79s 1회 요청당 평균 전체 실행 시간
총 테스트 시간 약 60초 전체 부하 테스트가 완료되기까지 걸린 시간

❗리소스 부족으로 서버가 다운됨

전체 리소스 사용량

  • 서버 다운으로 인한 모니터링 값 유실

어플리케이션별 리소스 사용량

image 16

image 17

APM 결과(API 지연 시간, 호출 수, 에러율)

image 18

5. 결과 분석

응답시간 분석

  • 동시 사용자 100명 이하에서는 평균 응답 시간 약 200ms로, 사용자 경험 측면에서 매우 빠르고 안정적인 성능을 보임
  • 하지만 400명 이상부터는 평균 응답 시간이 500ms 이상, 최대 4.84초 이상까지 증가하며, 성능 저하가 나타남.
  • 500명 부하 테스트 시, 응답은 정상적으로 반환되었으나 서버 자체가 다운되었으며, 이는 명백한 리소스 한계 초과를 나타냄.
  • 특이사항으로는, 모든 테스트에서 HTTP 요청 에러율은 **0.00%**로, 기능적 오류 없이 응답이 이루어짐. 이는 기능적 안정성은 확보되어 있지만, 성능 및 확장성 측면에서는 개선이 필요한 상태임을 의미함.

리소스 사용률 분석

  • 전체 테스트 전반에서 공통적으로 CPU 사용률은 90% 이상, 메모리도 거의 최대 용량까지 사용되는 모습을 확인할 수 있음
  • 특히 3차 및 4차 테스트(400~500 VU)에서는 CPU 및 RAM 사용률이 급격히 상승하며 시스템 자원이 포화 상태에 도달함.
  • 500명 동시 요청 테스트 시, CPU와 메모리가 한계치를 넘어서면서 실제 VM이 다운되는 현상이 발생했고, 이는 물리 자원의 부족이 성능 병목을 유발함을 보여줌

종합 판단

  • 응답 지연은 요청 수 증가에 따른 자원 부족 및 처리 병목으로 판단됨.
  • 특히, Trace에서 확인된 어플리케이션 처리 지연은 리소스 부족으로 인한, 메모리 부족, 스레드 부족, 잦은 GC 수행 등의 문제를 일으켰을 가능성이 높음.

6. 개선 방안 제안

  • 현재 서버 자원으로는 100건 이상의 동시 요청을 안정적으로 처리하기 어려우며, 인프라 확장 또는 구조적 최적화가 필요하다.
  • 현재 도커 컨테이너 환경으로의 마이그레이션을 통해 nextjs, springboot, mysql을 각 각의 인스턴스로 분리 예정이므로, 마이그레이션 전에는 사용자 수 100명에 맞춰 인스턴스 리소스를 CPU 2코어, RAM 8GB까지 늘리는 것을 제안한다.

7. 부록

  • 테스트 스크립트: /home/devops/stress-testing/get-message-test.js

테스트 스크립트

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  vus: 500,       
  duration: '30s', 
};

// 테스트할 API 정보
const BASE_URL = '<https://dev.hertz-tuning.com>'; 
const ENDPOINT = '/api/v1/channel?page=0&size=10';
const ACCESS_TOKEN = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI3IiwiaWF0IjoxNzQ4MzUwNDQ1LCJleHAiOjE3NDk1NjAwNDV9.jrU_9DS5dLNwXZHGOzcyt1TLbE5MqmuRqzMBEOskdio'; // 실제 토큰으로 교체

export default function () {
  const url = `${BASE_URL}${ENDPOINT}`;

  const params = {
    headers: {
      Authorization: `Bearer ${ACCESS_TOKEN}`,
      'Content-Type': 'application/json',
    },
  };

  const res = http.get(url, params);

  check(res, {
    '응답 코드가 200이어야 함': (r) => r.status === 200,
    '응답이 JSON 형식임': (r) => {
      try {
        JSON.parse(r.body);
        return true;
      } catch (e) {
        return false;
      }
    },
    '채널 리스트가 포함되어야 함': (r) => r.body.includes('channelRoomId'),
  });

  sleep(5);
}
⚠️ **GitHub.com Fallback** ⚠️