카테고리 없음

K6를 활용한 API 부하 테스트 및 모니터링

밤린 2024. 12. 10. 09:52

안녕하세요! 오늘은 K6를 활용하여 API 부하 테스트를 진행하고, 테스트 결과를 모니터링한 경험을 공유하려고 합니다. 이번 테스트에서는 특정 API의 동시 접속 처리 성능을 평가하고, 테스트 데이터를 InfluxDB와 Grafana를 이용해 시각화하는 방법도 다뤄보겠습니다.


1. 테스트 배경

현업에서 API의 성능을 보장하기 위해 부하 테스트는 필수적입니다. 특히, 예상 사용자가 급증하는 이벤트 시기나 새로운 기능이 배포될 때 시스템 안정성을 확인하기 위해 부하 테스트는 중요한 지표를 제공합니다.

목표

  1. 특정 API들이 동시 다중 사용자 요청을 얼마나 잘 처리하는지 확인.
  2. 회원가입, 위치 정보 조회, 병원 거리 계산 API의 부하를 시뮬레이션.
  3. 테스트 데이터를 수집하고 시각화하여 병목 구간을 식별.

2. 테스트 환경

사용 도구

  1. K6: 부하 테스트 스크립트를 작성하고 실행.
  2. InfluxDB: K6로부터 성능 데이터를 수집.
  3. Grafana: InfluxDB에 저장된 데이터를 시각화.

테스트 구성

  • URL: https://*******.com (보안을 위해 URL은 마스킹 처리되었습니다.)
  • 주요 테스트 API:
    1. 회원가입 API: /auth/signup - 새로운 사용자를 등록합니다.
    2. 위치 정보 조회 API: /hospital/location - 특정 위치 근처의 병원을 조회합니다.
    3. 병원 거리 계산 API: /hospital/distance - 사용자의 위치에서 병원까지의 거리를 계산합니다.
  • 데이터베이스: InfluxDB를 사용해 성능 데이터를 저장.
  • 대시보드: Grafana를 통해 실시간으로 모니터링.

3. K6 스크립트 작성

테스트는 회원가입에 10%, 위치 정보 조회에 60%, 병원 거리 계산에 30% 확률로 요청을 분배하여 진행했습니다.

테스트 스크립트 (K6)

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

export const options = {
  stages: [
    { duration: '1m', target: 50 }, // 1분 동안 50명의 사용자로 증가
    { duration: '3m', target: 100 }, // 3분 동안 100명의 사용자 유지
    { duration: '1m', target: 0 }, // 1분 동안 사용자 감소
  ],
};

const BASE_URL = 'https://*******.com'; // 서버 URL 마스킹 처리

export default function () {
  const rand = Math.random(); // 랜덤 값 생성

  // 회원가입 (10%)
  if (rand < 0.1) {
    const loginId = `user_${Math.random().toString(36).substring(7)}`;
    const signupRes = http.post(`${BASE_URL}/auth/signup`, JSON.stringify({
      loginId: loginId,
      name: 'Test User',
      password: 'password123',
      email: `${loginId}@example.com`,
      tel: '010-1234-5678',
      certificate: 'CERT123',
      organization: 'Test Organization',
    }), { headers: { 'Content-Type': 'application/json' } });

    check(signupRes, {
      'POST /auth/signup 상태 코드가 200': (r) => r.status === 200,
      'POST /auth/signup 응답에 성공 메시지가 있음': (r) => signupRes.json().message && signupRes.json().message.includes('회원가입이 요청되었습니다'),
    });

    return; // 회원가입 후 다른 API 호출은 하지 않음
  }

  // 랜덤 API 호출
  if (rand < 0.7) { // 10% ~ 70%: /hospital/location (60%)
    const locationRes = http.get(`${BASE_URL}/hospital/location?lat=37.5665&lon=126.9780&range=1000`);
    check(locationRes, {
      'GET /hospital/location 상태 코드가 200': (r) => r.status === 200,
    });
  } else { // 70% ~ 100%: /hospital/distance (30%)
    const distanceRes = http.post(`${BASE_URL}/hospital/distance`, JSON.stringify({
      lat: 37.5665,
      lon: 126.9780,
      range: 1000,
    }), { headers: { 'Content-Type': 'application/json' } });
    check(distanceRes, {
      'POST /hospital/distance 상태 코드가 200': (r) => r.status === 200,
    });
  }

  sleep(1);
}

4. 테스트 실행

K6 실행 명령어

k6 run --out influxdb=http://<InfluxDB_IP>:8086/k6 <스크립트_파일명>.js

여기서 <InfluxDB_IP>는 InfluxDB가 실행 중인 서버의 IP 또는 도메인입니다. 위 명령어는 테스트 데이터를 InfluxDB로 전송합니다.


5. 결과 모니터링

Grafana 시각화

Grafana에서 K6 데이터를 실시간으로 시각화했습니다. 주요 지표는 다음과 같습니다:

  1. 초당 요청 수 (RPS): 시스템의 처리 능력을 평가.
  2. 응답 시간: 평균, 최댓값, 95% 백분위수.
  3. 성공률: 상태 코드가 200인 요청의 비율.


6. 테스트 결과 및 결론

주요 결과

  1. 회원가입 API:
    • 10%의 요청이 회원가입 API로 분배되었습니다.
    • 요청당 평균 응답 시간: 160ms.
    • 성공률: 99.9% (몇몇 요청은 처리 지연으로 실패).
  2. 위치 정보 조회 API:
    • 60%의 요청이 위치 정보 조회 API로 분배되었습니다.
    • 요청당 평균 응답 시간: 30.2ms.
    • 성공률: 100%.
  3. 병원 거리 계산 API:
    • 30%의 요청이 병원 거리 계산 API로 분배되었습니다.
    • 요청당 평균 응답 시간: 150ms.
    • 성공률: 98% (고부하 시 일부 요청 실패).

결론

  • 테스트 결과를 통해 위치 정보 조회 API는 매우 안정적임을 확인했습니다.
  • 병원 거리 계산 API는 고부하 상황에서 일부 요청이 실패하므로 추가 최적화가 필요합니다.
  • 회원가입 API는 안정적으로 작동하지만, 응답 시간을 개선할 여지가 있습니다.