본문 바로가기
개발

Grafana K6를 이용하여 부하 테스트 해보기

by 방구쟁이 2024. 10. 27.
728x90

 이번에는 Kafka Consumer를 개발하면서 실제로 트래픽 처리에 대한 부하테스트를 진행하고 싶었습니다. 일반적으로 부하 테스트를 위해 사용할 수 있는 도구는 다양한데, 대표적으로 Apache JmeterGatling, kafka에서 제공하는 kafka-producer-perf-test & kafka-consumer-perf-test, Grafana K6 등이 존재합니다.

 저는 이 중 kafka-perf-testGrafana k6를 사용하여 부하테스트를 진행하였습니다. Grafana K6 경험을 기술하기 전 K6을 사용하기 전에 이용해본 Kafka shell을 간단하게 살펴보고자 합니다.

 

1.  kafka-producer-perf-test & kafka-consumer-perf-test 테스트

 첫번째로 kafka에서 제공하는 shell을 사용하여 테스트를 진행하였습니다. 따로 설정할 필요없었기 때문에 간단히 실행시켜 테스트를 할 수 있는 장점이 있었습니다. kafka-producer-perf-test & kafka-consumer-perf-test 쉘은 특정 Topic을 개수, 사이즈 등을 설정하여 메세지큐로 전송하고, Consumer에서 설정한 갯수만큼의 message를 처리한 결과를 분석한 결과를 제공합니다.

 쉘스크립트로 실행하여 테스트하며 아래와 같이 원하는 값들을 설정할 수 있는 옵션을 제공합니다.

/opt/kafka_mobwith/bin/kafka-producer-perf-test.sh --topic {{토픽명}} --num-records 1000 --record-size 100 --throughput 100 --producer-props bootstrap.servers={{ip:port}}

/opt/kafka_mobwith/bin/kafka-consumer-perf-test.sh --topic {{토픽명}} --bootstrap-server {{ip:port}} --group {{컨슈머 그룹명}} --messages 1000 --timeout 60000

 

  해당 테스트 도구를 사용할 경우 Producer를 통해 전송할 메세지는 설정한 size의 해당하는 임의의 문자열로 실제 consumer에서 처리 하는 메세지와 달라 실제 consumer의 로직을 수행하는 성능을 테스트할 수 없는 단점이 있었습니다.

 

실행 결과

- kafka-producer-perf-test

502 records sent, 100.3 records/sec (0.01 MB/sec), 5.0 ms avg latency, 487.0 ms max latency.
1000 records sent, 99.920064 records/sec (0.01 MB/sec), 3.08 ms avg latency, 487.00 ms max latency, 1 ms 50th, 4 ms 95th, 29 ms 99th, 487 ms 99.9th.


 총 1000개의 레코드가 성공적으로 전송, 초당 레코드 전송 : 약 100개, 초당 전송 데이터 크기 : 0.01 MB/sec, 평균 지연 시간 : 5.0 ms avg, 최대 지연 시간 : 487.0 ms 

분석한 결과 전송 성능이 안정적이며, 평균 지연 시간이 양호한 결과를 얻었습니다.

 

- kafka-consumer-perf-test

String 문자열을 Value로 전송하여 Consume 로직에서 에러 발생

 따라서 Grafana K6를 이용하여 실제 producer를 통해 topic을 전송하는 url을 요청하여 실제 로직을 수행하는 부하 테스트를 진행하였습니다.

 

2. Grafana K6 테스트

 간략히 K6를 소개하자면 다음과 같습니다.

 자바스크립트로 테스트 스크립트를 작성하는 Go 기반 오픈 소스 성능 테스트 툴로, 단일 인스턴스로 3만 이상의 동시 사용자 생성 가능하며 Jmeter 대비 가벼운 장점이 있다. Grafana를 통해 테스트 결과를 확인할 수 있습니다.

 K6을 이용한 테스트 방식은 아래와 같습니다. (K6 환경 구성은 생략 - 라이브러리 설치)

 

1. K6 테스트 코드 작성

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

export let options = {
    stages: [
      { duration: '10s', target: 30 },
      { duration: '1m', target: 100 },
      { duration: '20s', target: 0 },
    ],
  };
  
  function makeImpUrl(){
      const url = "https://devdsp.mobwith.co.kr/search/image";
      
      let params = "?zone=10886272";
      params += "&siteCode=0415364bb33d4fa3867a04a9c51397f7"
      params += "&keyword=%EC%B2%AD%EB%B0%94%EC%A7%80"
      params += "&spgSeq=1"
      params += "&spiSeq=2"
      params += "&skgSeq=14"
      params += "&auid="
      params += "&adid=35337fe9-f9b2-416b-8198-9e80d97e9d45"
      return url + params;
  }
  
  export default function () {
      let url = makeImpUrl();
      let res = http.get(url);

      check(res, {
           'status is 200': (r) => r.status === 200,
           'transaction time OK': (r) => r.timings.duration < 400,
      });

      sleep(1);
  }
  • options의 stages로 부하 설정 : 10초 동안 30명까지 증가 > 1분 동안 100명 유지 > 20초 동안 0명으로 감소
  • K6의 http.get(url)를 통하여 URL 요청

 

2. 작성한 K6 javascript 실행

k6 run load_test.js

 

3. 테스트 결과 분석

(아래는 테스트 결과 예시이다)

* 테스트 결과

PS C:\Users\Desktop\k6> k6 run .\load_test.js

         /\      Grafana   /‾‾/
    /\  /  \     |\  __   /  /
   /  \/    \    | |/ /  /   ‾‾\
  /          \   |   (  |  (‾)  |
 / __________ \  |_|\_\  \_____/

     execution: local
        script: .\load_test.js
        output: -

     scenarios: (100.00%) 1 scenario, 10 max VUs, 1m40s max duration (incl. graceful stop):
              * default: Up to 10 looping VUs for 1m10s over 2 stages (gracefulRampDown: 30s, gracefulStop: 30s)


     data_received..................: 14 MB 197 kB/s
     data_sent......................: 95 kB 1.4 kB/s
     http_req_blocked...............: avg=779.6µs  min=0s     med=0s      max=205.72ms p(90)=0s       p(95)=0s
     http_req_connecting............: avg=117.11µs min=0s     med=0s      max=6.41ms   p(90)=0s       p(95)=0s
     http_req_duration..............: avg=8.64ms   min=5.02ms med=7.84ms  max=91.21ms  p(90)=11ms     p(95)=11.97ms
       { expected_response:true }...: avg=8.64ms   min=5.02ms med=7.84ms  max=91.21ms  p(90)=11ms     p(95)=11.97ms
     http_req_failed................: 0.00% 0 out of 708
     http_req_receiving.............: avg=765.68µs min=0s     med=702.4µs max=5.77ms   p(90)=1.62ms   p(95)=1.93ms
     http_req_sending...............: avg=105.37µs min=0s     med=0s      max=1.27ms   p(90)=452.43µs p(95)=556.27µs
     http_req_tls_handshaking.......: avg=570.18µs min=0s     med=0s      max=181.46ms p(90)=0s       p(95)=0s
     http_req_waiting...............: avg=7.77ms   min=4.51ms med=7.03ms  max=90.5ms   p(90)=10.51ms  p(95)=11.29ms
     http_reqs......................: 708   10.03341/s
     iteration_duration.............: avg=1.01s    min=1.01s  med=1.01s   max=1.36s    p(90)=1.02s    p(95)=1.02s
     iterations.....................: 354   5.016705/s
     vus............................: 1     min=1        max=10
     vus_max........................: 10    min=10       max=10


running (1m10.6s), 00/10 VUs, 354 complete and 0 interrupted iterations
default ✓ [======================================] 00/10 VUs  1m10s

 

부하 테스트 케이스는 2가지로 진행되었습니다.

{ duration: '10s', target: 30 },
{ duration: '1m', target: 100 },
{ duration: '20s', target: 0 },
  • 실행 로직에 sleep을 주지 않아 사용자 한명이 1초당 여러번의 url을 호출하여 예상 기대값 이상 호출
  • 약 16만 건 요청에 대한 노출 수 적재 및 원장/서브 합계 일치
  • 에러 로그 및 특이사항 없음

 

{ duration: '1m', target: 10 },
{ duration: '10s', target: 0 },

sleep(1sec)을 추가하여 테스트 진행. 354번 반복하여 SA_IMPRESSION TOPIC을 354번 전송하는 URL을 호출

  • 노출 수 354 증가 확인
  • 원장/서브 테이블 노출 수 합계 일치 확인
  • 특이사항 없음

 

4. 결론

 테스트 결과, 개발 서버 환경에서 분당 100명의 사용자가 0.25초마다 요청을 전송해도 모두 안정적으로 처리됨을 확인하였습니다. K6를 활용한 부하 테스트를 통해, 향후 상용 서비스 배포 전 예상 트래픽 수준에서 테스트를 진행하여 서버 과부하를 예방할 수 있을 것으로 기대하며 위 포스팅을 마무리 하겠습니다.

 감사합니다.

k6 부하 테스트 실행 결과 화면

 

728x90

댓글