📗 스터디#Web#Testing
k6로 API 성능 테스트하기
2024-12-03 | 🕒 읽는 데 0분 예상작성자
u
카테고리
📗 스터디
작성일
‣
태그
Web
Testing
설명
상태
배포됨
최하위 정렬
최하위 정렬
forest_분류
forest_날짜
k6란?
k6는 Grafana Labs에서 개발한 오픈 소스 부하 테스트 도구이다. K6는 API 엔드포인트에 대한 성능 테스트를 쉽게 수행할 수 있게 해준다.
k6의 특징과 장점은 다음과 같다.
- JavaScript 기반: k6는 JavaScript를 사용하여 테스트 스크립트를 작성할 수 있게 해준다. 이는 많은 개발자들에게 친숙한 언어로, 학습 곡선을 낮추고 생산성을 높인다.
- 높은 성능: Go 언어로 작성되어 있어, 적은 리소스로도 높은 성능을 발휘한다. 이는 대규모 부하 테스트를 수행할 때 특히 유용하다.
- 확장성: 다양한 플러그인과 확장 기능을 지원하여 테스트 시나리오를 더욱 풍부하게 만들 수 있다.
- 통합 용이성: CI/CD 파이프라인과 쉽게 통합될 수 있어, 자동화된 성능 테스트 환경을 구축하기 용이하다.
- 다양한 프로토콜 지원: HTTP/HTTPS, WebSocket, gRPC 등 다양한 프로토콜을 지원한다.
- 결과 시각화: 테스트 결과를 다양한 형태로 시각화할 수 있어, 성능 분석이 용이하다.
설치
필자는 Windows 환경을 사용중이므로 이를 기준으로 설명하겠다. Windows에서 k6를 사용하기 위해서는
Chocolatey
패키지 매니저를 사용하는 것이 권장된다.Chocolatey를 설치하기 위해서는 PowerShell을 관리자 권한으로 실행해 아래 커맨드를 입력하면 된다.
> Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
설치가 완료되면
choco
명령어를 입력해 설치 여부를 확인해보자. 설치가 정상적으로 완료됐다면, 이제 아래 커맨드를 입력해 k6를 설치할 수 있다.$ choco install k6
테스트 실행
k6의 기본 테스트 스크립트 구조는 다음과 같다.
import http from 'k6/http'; import { check, sleep } from 'k6'; export const options = { vus: 10, duration: '30s', }; export default function () { const res = http.get('https://test.k6.io'); check(res, { 'status was 200': (r) => r.status == 200 }); sleep(1); }
이 코드는 10명의 가상 사용자(VU)가 30초 동안 https://test.k6.io에 GET 요청을 보내는 간단한 테스트를 수행한다.
가상 사용자(VU)란 실제 사용자의 행동을 시뮬레이션하는 가상의 동시 접속자를 말한다. 각 VU는 정의된 시나리오에 따라 독립적으로 작업을 수행하게 된다. 여기서 주의할 것은 VU가 요청의 수를 의미하는 것이 아니라는 것이다. 위 예시처럼 VU가 10이고, duration이 30초라면, 30초 동안 10명의 사용자가 지속적으로 요청을 보내는 것을 가정하는 테스트이다.
테스트를 시작하려면 터미널에 다음과 같이 명령어를 입력하면 된다.
$ k6 run 테스트코드파일.js
테스트가 종료되면 다음과 같이 결과가 출력된다.
표시된 결과에서 각 항목에 대한 설명은 다음과 같다.
항목 | 설명 | Type |
vus | 현재 활성화된 가상 사용자 | Guage |
vus_max | 가능한 최대 가상 사용자 수(리소스 미리 할당) | Guage |
iterations | 테스트에서 VU가 스크립트를 실행한 총 횟수 | Counter |
iteration_duration | main function의 전체 반복을 완료하는 데 소요된 시간 | Trend |
data_received | 데이터를 전달받은 양 | Counter |
data_sent | 데이터를 전송한 양 | Counter |
checks | 성공적으로 체크된 비율 | Rate |
http_reqs | 생성한 총 HTTP 요청 횟수 | Counter |
http_req_blocked | 요청을 시작하기 전 차단된(TCP connection slot 대기) 시간 | Trend |
http_req_connecting | 원격 호스트에 대한 TCP 연결을 설정하는 데 소요된 시간 | Trend |
http_tls_handshaking | 원격 호스트와의 hand shaking 세션에 소요된 시간 | Trend |
http_req_sending | 원격 호스트에 데이터를 전송하는 데 소요된 시간 | Trend |
http_req_waiting | 원격 호스트로부터 응답을 대기하는 데 소요된 시간 | Trend |
http_req_receiving | 원격 호스트로부터 응답을 수신하는 데 소요된 시간 | Trend |
http_req_duration | 요청의 총 시간 (http_req_sending + http_req_waiting + http_req_receiving) | Trend |
http_req_failed | 요청이 실패한 비율 | Rate |
k6는 다양한 고급 기능을 제공하여 복잡한 성능 테스트 시나리오를 구현할 수 있게 해준다. 주요 고급 기능들을 소개하고, 각 기능별로 예시 코드를 통해 살펴보도록 하겠다.
단계별 부하 증가 (Stages)
Stages 기능을 사용하면 시간에 따라 가상 사용자(VU) 수를 동적으로 조절할 수 있다. 이는 점진적인 부하 증가나 스파이크 테스트 등을 수행할 때 유용하다.
import http from 'k6/http'; export const options = { stages: [ { duration: '30s', target: 20 }, // 30초 동안 20명까지 증가 { duration: '1m30s', target: 10 }, // 1분 30초 동안 10명으로 감소 { duration: '20s', target: 0 }, // 20초 동안 0명으로 감소 ], }; export default function () { http.get('https://test.k6.io'); }
이 테스트에서는 처음 30초 동안 VU를 20명까지 증가시키고, 그 다음 1분 30초 동안 10명으로 줄인 후, 마지막 20초 동안 0명으로 감소시킨다.
임계값 (Thresholds)
임계값을 설정하여 테스트의 성공/실패 기준을 정의할 수 있다.
import http from 'k6/http'; export const options = { thresholds: { http_req_duration: ['p(95)<500'], // 95%의 요청이 500ms 이내에 완료되어야 함 http_req_failed: ['rate<0.1'], // 요청 실패율이 10% 미만이어야 함 }, }; export default function () { http.get('https://test.k6.io'); }
이 스크립트는 95%의 요청이 500ms 이내에 완료되어야 하며, 요청 실패율이 10% 미만이어야 한다는 조건을 설정한다. 아래 사진과 같이 만약 설정한 조건을 만족하지 못한 항목에는
X
가 표시되며, 만족한 항목에는 체크가 표시된다.체크 (Checks)
체크를 사용하여 응답의 유효성을 검증할 수 있다.
import http from 'k6/http'; import { check } from 'k6'; export default function () { let res = http.get('https://test.k6.io'); check(res, { '상태 200': (r) => r.status === 200, '본문에 "Welcome" 포함': (r) => r.body.includes('Welcome'), }); }
이 스크립트는 응답의 상태 코드가 200인지, 그리고 응답 본문에 "Welcome"이라는 텍스트가 포함되어 있는지 확인한다. 위 예제에 대한 결과는 아니지만, 필자가 진행 중인 프로젝트에 사용한 테스트 결과 화면은 아래와 같다. 각 스텝에 대한 테스트가 완료되면 체크 표시를 통해 응답이 정상적으로 반환되었음을 확인할 수 있다.
그룹화 (Grouping)
그룹화를 사용하면 관련된 요청들을 논리적 단위로 묶을 수 있다. 이는 결과 분석 시 유용하다.
import http from 'k6/http'; import { group, check } from 'k6'; export default function () { group('접속 테스트', function () { let res = http.get('https://test.k6.io'); check(res, { '상태 200': (r) => r.status === 200 }); }); group('로그인 테스트', function () { let res = http.post('https://test.k6.io/login', { username: 'testuser', password: 'testpass' }); check(res, { '로그인 성공': (r) => r.status === 200 }); }); }
이처럼 페이지 접속, 로그인과 같이 각 작업들을 그룹으로 묶어 테스트할 수 있다.
사용자 정의 메트릭
k6에서는 사용자 정의 메트릭을 생성하여 특정 이벤트나 조건을 추적할 수 있다. 매트릭 선언 시에 적절한 타입의 객체를 선언해주어야 하는데, 총 4가지로 구분된다.
- Counters - 값을 누적하여 계산
- Gauges - 최소, 최대, 마지막 값을 산출
- Rates - 0(False)이 아닌 값이 얼마나 자주 반환되는 지 체크(백분율)
- Trends - 평균, 백분위 수, 최빈값 등 다양한 통계 계산
import http from 'k6/http'; import { Counter, Rate } from 'k6/metrics'; const successfulLogins = new Counter('successful_logins'); const failedLogins = new Rate('failed_logins'); export default function () { let res = http.post('https://test.k6.io/login', { username: 'testuser', password: 'testpass' }); if (res.status === 200) { successfulLogins.add(1); } else { failedLogins.add(1); } }
이 스크립트는 성공한 로그인 수와 실패한 로그인 비율을 추적한다.
이외에도 k6는 다양한 옵션과 기능들을 제공하고 있으며, Grafana와 같은 시각화 도구를 이용해 결과를 분석해볼 수도 있다. 공식 문서가 상당히 잘 작성되어 있으니 참고하면 좋을 것 같다.