티스토리 뷰

Server

[Server] K6 부하 테스트 시나리오 작성하고 결과 지표 분석하기(K6 Load Testing)

망나니개발자 2025. 4. 1. 10:00
반응형

 

 

1. K6 부하 테스트 시나리오 작성하고 결과 지표 분석하기(K6 Load Testing)


[ K6 부하테스트 스크립트 작성하기 ]

과거에는 Ngrinder 또는 JMeter 등을 활용해 부하 테스트 또는 성능 테스트를 진행했었는데, 최근에는 그라파나(Grafana) 진영에서 만든 K6 역시 자주 사용되곤 한다. K6 깃허브 페이지의 Releases에 접속하여 실행 가능한 파일을 받고, 다음과 같은 실행 명령어를 통해 손쉽게 부하 테스트를 진행할 수 있다. K6의 핵심 설계 목표는 최고의 개발자 경험을 제공해주는 것이라고 하는데, 손쉬운 실행 방법에서도 이를 체감할 수 있다.

./k6 run --vus 3 --duration 5s script.js

 

 

위의 명령어는 가상의 사용자 3명을 기준으로 5초 동안 부하를 지속함을 의미한다. 즉, 3명의 사용자가 API 요청을 반복적으로 보내게 되며, 해당 작업은 5초 동안 유지되는 것이다.

실제 실행시킬 스크립트는 다음과 같은 모습으로 작성할 수 있다. 관련 예시 자료는 K6 공식 홈페이지에서 참고할 수 있다.

import http from "k6/http";
import { group, check, sleep } from "k6";

const numUsers = 250; // the number of vusers
const serverName = "mangkyu"
const testId = new Date().getTime();
export const options = {
  scenarios: {
    open_model: {
      // option details : <https://k6.io/docs/using-k6/scenarios/executors/ramping-arrival-rate/#options>
      executor: 'ramping-arrival-rate',
      startRate: 100,
      timeUnit: '20s', // 요청이 만들어지는 기본 단위
      preAllocatedVUs: 10,
      maxVUs: numUsers,
      stages: [
          // Start 100 iterations per `timeUnit` for the first 20 seconds.
          // 초기 부하: 첫 20초 동안 진행되며, 매 20초 동안 요청이 200개 만들어지므로 5 TPS
          { target: 100, duration: '20s' },

          // Linearly ramp-up to starting 8000 iterations per `timeUnit` over the following 1 minute.
          // 점진적 증가: 1분 동안 받는 요청을 10000 회로 증가시킴, 매 20초 동안 요청이 10000개 만들어지므로 500 TPS
          { target: 10000, duration: '1m' },

          // Continue starting 8000 iterations per `timeUnit` for the following 1 minute.
          // 최대 부하 유지: 1분 동안 받는 요청이 10000으로 지속됨, 매 20초 동안 요청이 10000개 만들어지므로 500 TPS
          { target: 10000, duration: '1m' }, //pod 당 최대 400 tps(400 * 20s(timeUnit))

          // Linearly ramp-down to starting 60 iterations per timeUnit over the last 20 seconds.
          // 점진적 감소: 마지막 20초 동안 진행되며, 매 20초 동안 요청이 100개 만들어지므로 5 TPS
          { target: 100, duration: '20s' },
      ]
    },
  },
  tags: {
    testid: `${serverName}-${testId}`
  },
  thresholds: {
    http_req_duration: ['p(99)<1000'], // 99% of requests must complete below 1s
  },
};

const BASE_URL = "localhost:8080";
// Sleep duration between successive requests.
// You might want to edit the value of this variable or remove calls to the sleep function on the script.
const SLEEP_DURATION = 0.1;
// Global variables should be initialized.

let userId = "123123";
let userName = "MangKyu";

export default function() {
    group("/api/v1/users/{userId}", () => {
      let url = BASE_URL + `/api/v1/users/${userId}`;
      let params = {headers: {"Content-Type": "application/json", "Accept": "application/json"}};

        // Request No. 1
        let request = http.get(url, params);
        check(request, {
            "OK": (r) => r.status === 200
        });
        sleep(SLEEP_DURATION);
    });

    group("/api/v1/users", () => {
        let url = BASE_URL + `/api/v1/users`;
        // Request No. 1
        let body = {"userName": `${userName}`};
        let params = {headers: {"Content-Type": "application/json", "Accept": "application/json"}};
        let request = http.post(url, body, params);
        check(request, {
          "OK": (r) => r.status === 200
        });
        sleep(SLEEP_DURATION);
    });
}

 

 

 

[ K6 부하 테스트의 결과 지표 분석하기 ]

K6로 부하 테스트를 진행하면 다음과 같은 결과를 얻게 되는데, 해당 지표에 대하여 분석해보도록 하자.

          /\\      |‾‾| /‾‾/   /‾‾/   
     /\\  /  \\     |  |/  /   /  /    
    /  \\/    \\    |     (   /   ‾‾\\  
   /          \\   |  |\\  \\ |  (‾)  | 
  / __________ \\  |__| \\__\\ \\_____/ .io

  execution: local
     script: services/family-promotion/script.js
     output: -

  scenarios: (100.00%) 1 scenario, 3 max VUs, 35s max duration (incl. graceful stop):
           * default: 3 looping VUs for 5s (gracefulStop: 30s)

     █ /api/v1/users/{userId}

       ✓ OK

     █ /api/v1/users

       ✓ OK

     checks.........................: 100.00% ✓ 1200  
     data_received..................: 75 kB   13 kB/s
     data_sent......................: 31 kB   5.5 kB/s
     group_duration.................: avg=137.3ms  min=117.36ms med=123.72ms max=477.97ms p(90)=147.86ms p(95)=170.92ms
     http_req_blocked...............: avg=5.1ms    min=2µs      med=7µs      max=204.57ms p(90)=14.3µs   p(95)=23.09µs 
     http_req_connecting............: avg=147.83µs min=0s       med=0s       max=5.94ms   p(90)=0s       p(95)=0s      
   ✓ http_req_duration..............: avg=31.05ms  min=16.81ms  med=22.94ms  max=172.32ms p(90)=47.49ms  p(95)=69.65ms 
       { expected_response:true }...: avg=31.05ms  min=16.81ms  med=22.94ms  max=172.32ms p(90)=47.49ms  p(95)=69.65ms 
     http_req_failed................: 0.00%   ✓ 0120
     http_req_receiving.............: avg=463.82µs min=19µs     med=201.5µs  max=7.81ms   p(90)=830.4µs  p(95)=1.13ms  
     http_req_sending...............: avg=49.39µs  min=6µs      med=33µs     max=1.21ms   p(90)=57.2µs   p(95)=90.19µs 
     http_req_tls_handshaking.......: avg=3.8ms    min=0s       med=0s       max=152.8ms  p(90)=0s       p(95)=0s      
     http_req_waiting...............: avg=30.54ms  min=16.04ms  med=22.12ms  max=171.82ms p(90)=47.01ms  p(95)=65.08ms 
     http_reqs......................: 120     20.874604/s
     iteration_duration.............: avg=825.33ms min=739.14ms med=782.64ms max=1.1s     p(90)=1.1s     p(95)=1.1s    
     iterations.....................: 20      3.479101/s
     vus............................: 3       min=3       max=3
     vus_max........................: 3       min=3       max=3

running (05.7s), 0/3 VUs, 20 complete and 0 interrupted iterations
default ✓ [======================================] 3 VUs  5s

 

 

 

그라파나 진영은 대시보드를 간편하게 구성할 수 있도록 기본적인 템플릿을 제공하고 있어 대시보드를 손쉽게 구성할 수 있다. (참고로 해당 레포지토리는 K6에 합쳐저 조만간 아카이빙될 것이라고 하는데, K6 레포지토리에는 대시보드 템플릿이 없으니 가져다 쓰도록 하자.)

 

 

위의 대시보드는 다음의 포스팅을 통해 참고하여 구성할 수 있는데, 해당 대시보드에서 나타내는 지표는 각각 다음과 같다.

  • 전체 요청의 수
    • 부하 테스트가 진행된 시간 동안 만들어진 전체 요청의 수
    • k6_http_reqs_total에서 구할 수 있음
  • 성공/실패한 요청의 수
    • 실행 결과에 따라 에러 응답이 높지 않은지 확인 필요
    • 모든 http 요청에는 태그가 적용되는데, 그 중에서 expected_response 태그(해당 응답이 정상이었는지를 확인)를 통해 식별할 수 있음
    • k6_http_reqs_total에서 expected_response가 false인 경우를 필터링하여 계산할 수 있음
  • Peak RPS
    • 요청 시간 동안 가장 높은 순간적인 RPS 값
    • 전체 요청 k6_http_reqs_total 에서 시간에 따른 변화율(irate)로 계산하면 구할 수 있음
  • P99 Response Time
    • 99번째 백분위수(99th percentile, P99) 응답 시간으로, 99%의 요청이 해당 시간 이하로 처리됨을 의미함
    • k6_http_req_duration_p99에서 avg 하여 구할 수 있음
  • 전송된 데이터
    • 요청을 처리하기 위해 전달한 데이터의 크기
    • k6_data_sent_total에서 sum하여 구할 수 있음
  • 응답된 데이터
    • 응답으로 전달된 데이터의 크기
    • k6_data_received_total에서 sum하여 구할 수 있음

 

 

기본적으로 구성 가능한 내용들은 제공되고 있으니 이를 적극 활용하여 구축하도록 하자.

 

 

참고 자료

 

 

 

 

 

 

 

 

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함