IT STUDY LOG
Sprint - aws EC2와 K6를 이용한 성능테스트 본문
#학습 목표
- k6 도구 활용법을 학습
- 성능 테스트 유형별 스크립트를 작성
- aws ec2 인스턴스를 모니터링
- aws에서 제공하는 버스트 크레딧을 이해
#과제 항목별 진행 상황
✏️ aws ec2 인스턴스 생성 및 성능 테스트를 위해 서버를 컨테이너로 배포
Step 1 : EC2 인스턴스 생성
- 버스트 기능이 있는 t2micro를 생성하고 운영체제는 ubuntu 20.04로 설정


Step 2 : EC2 인스턴스에 SSH 접속 후 도커 설치
1) SSH 접속
$ ssh -i "****.pem" ubuntu@ec2-**-***-**-**.ap-northeast-2.compute.amazonaws.com
The authenticity of host 'ec2-**-**-**-**.ap-northeast-2.compute.amazonaws.com (**.***.**.**)' can't be established.
ECDSA key fingerprint is SHA256:*
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
2) 도커 설치 스크립트 실행
#!/bin/sh
#업데이트 및 HTTP 패키지 설치
sudo apt update -y
sudo apt-get install -y ca-certificates \
curl \
software-properties-common \
apt-transport-https \
gnupg \
lsb-release
# GPG 키 및 저장소 추가
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 도커엔진 설치
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io
Step 3 : 도커 컨테이너 배포
1) 도커 허브에서 가져온 이미지를 바탕으로 컨테이너 배포
$ sudo docker run --name <서버명> -d -p 8080:8080 sebcontents/cozserver:1.0
2) 성공적으로 배포되었는지 확인
$ curl http://localhost:8080
<h1>CozServer에 오신 것을 환영합니다!</h1>
<div>버전: v1.0</div>
<div>파드 이름: 343ecf8c14d6</div>
<div>::ffff:172.17.0.1에서 오셨군요!</div>
✏️ k6 설치
Step 1 : snapd를 이용해 k6 설치
$ sudo apt update
$ sudo apt install snapd
$ sudo snap install k6
Download snap "k6" (29) from channel "stable" |
k6 v0.43.1 from Thomas Bille (tbmb) installed
Step 2 : 다양한 테스트 스크립트 실행
# 로컬에 있는 스크립트를 EC2 인스턴스로 업로드
# scp -i "키페어 경로 주소" [-r 옵션, 디렉터리] <파일/디렉터리명> <EC2 인스턴스 퍼블릭 주소>[-r 옵션 사용시, :/home/ubuntu 등 디렉터리 명시]
# ec2 인스턴스에서 로컬로 다운로드 받을 경우, 파일/디렉토리 위치를 반대로 입력하면 됨
$ scp -i "***.pem" -r ./k6_practice ubuntu@ec2-**-***-**-***.ap-northeast-2.compute.amazonaws.com:/home/ubuntu
✏️ k6를 이용해 EC2 인스턴스 성능 테스트
Step 0 : 부하(Load) 테스트 유형
유형 | vus/처리량 | 지속 | 사용 사례 |
smoke | 낮은 | 빠름(초 또는 분) | 새로운 코드나 변경이 있을 때마다. 스크립트, 기준 시스템 메트릭 및 변경 사항의 편차를 확인합니다. |
load | 평균 생산량 | 중간 (15-60분) | 종종 시스템이 평균 사용으로 성능을 유지하는지 확인하기 위해 |
stress | 높음(평균 이상) | 중간 (15-60분) | 시스템이 관리 방법을 확인하기 위해 평균 이상의 부하를 받을 수 있는 경우 |
soak | 평균 | 긺 (시간) | 장기간 연속 사용 시 체크 시스템으로 변경 후 |
spike | 매우 높음 | 빠름(초에서 분) | 드물게 시스템 위험이 갑자기 돌진할 때 |
breakpoint | 쉬는 시간까지 증가 | 필요한 만큼 | 시스템의 상한선을 찾기 위해 몇 번 |
Step 1 : 각각의 스크립트를 실행해 보고 ec2 인스턴스의 CPU 사용률 대시보드를 확인
1) basic test 실행
// basic_test.js
import http from 'k6/http';
import { sleep } from 'k6';
export let options = {
insecureSkipTLSVerify: true,
noConnectionReuse: false,
vus: 10,
duration: '30s'
};
export default () => {
http.get('http://localhost:8080')
sleep(1);
};
1-2) 스크립트 실행 결과
$ k6 run basic_test.js
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: basic_test.js
output: -
scenarios: (100.00%) 1 scenario, 10 max VUs, 1m0s max duration (incl. graceful stop):
* default: 10 looping VUs for 30s (gracefulStop: 30s)
data_received..................: 134 kB 4.4 kB/s
data_sent......................: 24 kB 792 B/s
http_req_blocked...............: avg=1.15ms min=3.78µs med=5.31µs max=46.08ms p(90)=8.05µs p(95)=34.03µs
http_req_connecting............: avg=149.89µs min=0s med=0s max=9.56ms p(90)=0s p(95)=0s
http_req_duration..............: avg=4.81ms min=886.72µs med=4.12ms max=21.74ms p(90)=8.24ms p(95)=9.48ms
{ expected_response:true }...: avg=4.81ms min=886.72µs med=4.12ms max=21.74ms p(90)=8.24ms p(95)=9.48ms
http_req_failed................: 0.00% ✓ 0 ✗ 300
http_req_receiving.............: avg=63.35µs min=19.53µs med=36.28µs max=1.87ms p(90)=85.21µs p(95)=104.87µs
http_req_sending...............: avg=267.92µs min=9.7µs med=14.28µs max=7.58ms p(90)=56.42µs p(95)=892.14µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=4.48ms min=811.75µs med=3.86ms max=21.64ms p(90)=7.87ms p(95)=8.75ms
http_reqs......................: 300 9.903457/s
iteration_duration.............: avg=1s min=1s med=1s max=1.06s p(90)=1.01s p(95)=1.01s
iterations.....................: 300 9.903457/s
vus............................: 10 min=10 max=10
vus_max........................: 10 min=10 max=10
running (0m30.3s), 00/10 VUs, 300 complete and 0 interrupted iterations
default ✓ [======================================] 10 VUs 30s
2) load test 실행
- 평균 부하 테스트는 일반적인 부하에서 시스템이 어떻게 작동하는지 평가하며, 일반적인 부하는 프로덕션의 일상일 수도 있고 평균 순간일 수도 있음
2-1) load_test.js 코드
// load_test.js
import http from "k6/http";
import { sleep } from 'k6';
export let options = {
insecureSkipTLSVerify: true,
noConnectionReuse: false,
stages: [
{ duration: '5m', target: 100 },
{ duration: '10m', target: 100 },
{ duration: '5m', target: 0 },
],
thresholds: {
http_req_duration: ['p(99)<150'],
}
};
export default () => {
let respose = http.get("http://localhost:8080");
sleep(1);
};
2-2) 스크립트 실행 결과
$ k6 run load_test.js
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: load_test.js
output: -
scenarios: (100.00%) 1 scenario, 100 max VUs, 20m30s max duration (incl. graceful stop):
data_received..................: 40 MB 33 kB/s
data_sent......................: 7.2 MB 6.0 kB/s
http_req_blocked...............: avg=8.63µs min=3.23µs med=5.35µs max=15.74ms p(90)=7.28µs p(95)=11.25µs
http_req_connecting............: avg=508ns min=0s med=0s max=2.89ms p(90)=0s p(95)=0s
✓ http_req_duration..............: avg=5.8ms min=543.08µs med=2.36ms max=106.57ms p(90)=15.71ms p(95)=19.98ms
{ expected_response:true }...: avg=5.8ms min=543.08µs med=2.36ms max=106.57ms p(90)=15.71ms p(95)=19.98ms
http_req_failed................: 0.00% ✓ 0 ✗ 89571
http_req_receiving.............: avg=133.07µs min=17.6µs med=66.65µs max=32.74ms p(90)=241.38µs p(95)=271.32µs
http_req_sending...............: avg=275.35µs min=8.5µs med=14.04µs max=56.45ms p(90)=46.61µs p(95)=289.23µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=5.39ms min=483µs med=2.19ms max=86.73ms p(90)=14.72ms p(95)=18.67ms
http_reqs......................: 89571 74.603413/s
iteration_duration.............: avg=1s min=1s med=1s max=1.11s p(90)=1.01s p(95)=1.02s
iterations.....................: 89571 74.603413/s
vus............................: 1 min=1 max=100
vus_max........................: 100 min=100 max=100
running (20m00.6s), 000/100 VUs, 89571 complete and 0 interrupted iterations
default ✓ [======================================] 000/100 VUs 20m0s
3) stress test 실행
- 스트레스 테스트는 부하가 평소보다 무거울 때 시스템이 어떻게 작동하는지 평가함
- 스트레스 테스트의 부하 패턴은 평균 부하 테스트와 비슷하나, 주요 차이점은 더 높은 부하를 가한다는 점
3-1) stress_test.js 코드
// stress_test.js
import http from "k6/http";
import { sleep, check } from 'k6';
export let options = {
insecureSkipTLSVerify: true,
noConnectionReuse: false,
stage: [
{ duration: '2m', target: 100 },
{ duration: '5m', target: 100 },
{ duration: '2m', target: 200 },
{ duration: '5m', target: 200 },
{ duration: '2m', target: 300 },
{ duration: '5m', target: 300 },
{ duration: '2m', target: 400 },
{ duration: '5m', target: 400 },
{ duration: '10m', target: 0 },
],
};
export default function () {
const res = http.get('http://localhost:8080');
check(res, { 'status was 200': (r) => r.status == 200 });
sleep(1);
};
3-2) 스크립트 실행 결과
$ k6 run stress_test.js
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: stress_test.js
output: -
scenarios: (100.00%) 1 scenario, 400 max VUs, 38m30s max duration (incl. graceful stop):
* default: Up to 400 looping VUs for 38m0s over 9 stages (gracefulRampDown: 30s, gracefulStop: 30s)
running (02m04.4s), 100/400 VUs, 6371 complete and 0 inter
✓ status was 200
checks.........................: 100.00% ✓ 503151 ✗ 0
data_received..................: 224 MB 107 kB/s
data_sent......................: 40 MB 19 kB/s
http_req_blocked...............: avg=6.85µs min=3.22µs med=5.31µs max=16.32ms p(90)=6.16µs p(95)=8.03µs
http_req_connecting............: avg=340ns min=0s med=0s max=4.41ms p(90)=0s p(95)=0s
http_req_duration..............: avg=2.13ms min=555.81µs med=1.05ms max=160.51ms p(90)=3.51ms p(95)=6.84ms
{ expected_response:true }...: avg=2.13ms min=555.81µs med=1.05ms max=160.51ms p(90)=3.51ms p(95)=6.84ms
http_req_failed................: 0.00% ✓ 0 ✗ 503151
http_req_receiving.............: avg=124.85µs min=18.43µs med=74.89µs max=43.03ms p(90)=208.17µs p(95)=249.22µs
http_req_sending...............: avg=47.56µs min=8.17µs med=13.75µs max=49.6ms p(90)=37.65µs p(95)=52.29µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=1.96ms min=444.39µs med=857.16µs max=140.54ms p(90)=3.32ms p(95)=6.62ms
http_reqs......................: 503151 240.393445/s
iteration_duration.............: avg=1s min=1s med=1s max=1.16s p(90)=1s p(95)=1s
iterations.....................: 503025 240.333246/s
vus............................: 126 min=1 max=400
vus_max........................: 400 min=400 max=400
4) soak test 실행
- 평균 부하 테스트의 또다른 변형으로 장기간동한 수행하며 아래 사항을 분석
- 장기간에 걸친 시스템 성능 저하 및 리소스 낭비
- 확장된 기간 동안 시스템의 가용성 및 안정성
4-1) soak_test.js 코드
// soak_test.js
import http from "k6/http";
import { sleep, check } from 'k6';
export let options = {
insecureSkipTLSVerify: true,
noConnectionReuse: false,
stages: [
{ duration: '2m', target: 400 },
{ duration: '3h56m', target: 400 },
{ duration: '2m', target: 0 },
],
};
export default function () {
const res = http.get('http://localhost:8080');
check(res, { 'status was 200': (r) => r.status == 200 });
sleep(1);
};
4-2) 스크립트 실행 결과
$ k6 run soak_test.js
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: soak_test.js
output: -
scenarios: (100.00%) 1 scenario, 400 max VUs, 4h0m30s max duration (incl. graceful stop):
* default: Up to 400 looping VUs for 4h0m0s over 3 stages (gracefulRampDown: 30s, gracefulStop: 30s)
✓ status was 200
checks.........................: 100.00% ✓ 160029 ✗ 0
data_received..................: 71 MB 155 kB/s
data_sent......................: 13 MB 28 kB/s
http_req_blocked...............: avg=8.32µs min=3.32µs med=5.3µs max=17.11ms p(90)=6.14µs p(95)=9.01µs
http_req_connecting............: avg=1.74µs min=0s med=0s max=17.03ms p(90)=0s p(95)=0s
http_req_duration..............: avg=1.84ms min=561.48µs med=1.05ms max=58.59ms p(90)=2.6ms p(95)=5.45ms
{ expected_response:true }...: avg=1.84ms min=561.48µs med=1.05ms max=58.59ms p(90)=2.6ms p(95)=5.45ms
http_req_failed................: 0.00% ✓ 0 ✗ 160029
http_req_receiving.............: avg=125.26µs min=19.3µs med=79.66µs max=24.85ms p(90)=208.25µs p(95)=228.62µs
http_req_sending...............: avg=33.72µs min=8.87µs med=13.71µs max=24.74ms p(90)=37.84µs p(95)=57.76µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=1.68ms min=485.61µs med=857.2µs max=58.55ms p(90)=2.46ms p(95)=5.29ms
http_reqs......................: 160029 347.45119/s
iteration_duration.............: avg=1s min=1s med=1s max=1.05s p(90)=1s p(95)=1s
iterations.....................: 159629 346.58272/s
vus............................: 400 min=3 max=400
vus_max........................: 400 min=400 max=400
running (0h07m40.6s), 000/400 VUs, 159629 complete and 400 interrupted iterations
5) spike test 실행
- 스파이크 테스트는 시스템이 갑자기 대용량의 사용량이 급증할 때 살아남고 성능을 발휘하는지 확인하는 테스트로 가장 흔하지 않은 테스트 중 하나
5-1) spike_test.js 코드
// spike_test.js
import http from "k6/http";
import { sleep, check } from 'k6';
export let options = {
insecureSkipTLSVerify: true,
noConnectionReuse: false,
stages: [
{ duration: '10s', target: 100 },
{ duration: '1m', target: 100 },
{ duration: '10s', target: 1400 },
{ duration: '3m', target: 1400 },
{ duration: '10s', target: 100 },
{ duration: '3m', target: 100 },
{ duration: '10s', target: 0 },
],
};
export default function () {
const res = http.get('http://localhost:8080');
check(res, { 'status was 200': (r) => r.status == 200 });
sleep(1);
};
5-2) 스크립트 실행 결과
$ k6 run spike_test.js
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: spike_test.js
output: -
scenarios: (100.00%) 1 scenario, 1400 max VUs, 8m10s max duration (incl. graceful stop):
* default: Up to 1400 looping VUs for 7m40s over 7 stages (gracefulRampDown: 30s, gracefulStop: 30s)
running (1m18.8s), 1242/1400 VUs, 11404 complete and 0 interrupted iterat
default [=====>--------------------------------] 1242/1400 VUs 1m18.8s/7m40.0s
WARN[0489] Request Failed error="Get \"http://localhost:8080\": request timeout"
WARN[0489] Request Failed error="Get \"http://localhost:8080\": request timeout"
WARN[0489] Request Failed error="Get \"http://localhost:8080\": request timeout"
WARN[0489] Request Failed error="Get \"http://localhost:8080\": request timeout"
WARN[0489] Request Failed error="Get \"http://localhost:8080\": request timeout"
WARN[0489] Request Failed error="Get \"http://localhost:8080\": request timeout"
WARN[0494] Request Failed error="Get \"http://localhost:8080\": request timeout"
WARN[0494] Request Failed error="Get \"http://localhost:8080\": request timeout"
Step 2 : EC2 대시보드에서 aws burst credit(CPU 크레딧 사용량(개수) )와 CPU 크레딧 밸런스(개수)를 관찰
(1) basic test
(2) load test
(3) stress test
(4) soak test
(5) spike test
# TROUBLE SHOOTING LOG
📝 문제 1 : k6 테스트 실행 시 stage 필드를 찾을 수 없음
1. 현상
WARN[0000] There were unknown fields in the options exported in the script error="json: unknown field \"stage\""
2. 원인
- 옵션에 stage라는 필드가 존재하지 않음, k6 options document를 확인하면 필드명이 stage가 아닌 stages임을 알 수 있음
3. 해결 방안
- 스크립트의 stage를 stages로 변경
📝 문제 2 : k6 테스트 실행 시 request failed
1. 현상
WARN[0050] Request Failed error="Get \"https://localhost:8080\": http: server gave HTTP response to HTTPS client"
2. 원인
- 현재 로컬호스트 포트는 https가 아닌 http 통신을 수행하므로 발생하는 오류
3. 해결 방안
- k6 스크립트의 요청 주소를 http로 변경
📝 문제 3 : k6 테스트 실행 시 reference error
1. 현상
ERRO[0008] ReferenceError: check is not defined
running at file:///home/ubuntu/k6_practice/sprint_k6_test/stress_test.js:36:10(12) executor=ramping-vus scenario=default source=stacktrace
2. 원인
- check이 정의되지 않았기 때문에
3. 해결 방안
- check 메서드를 사용하기 위해 check을 import 해주어야 함
# references
https://k6.io/docs/using-k6/k6-options/how-to/
How to use options
How to set options in different places (with examples), how to override options, and how to access the value of an option as the test runs.
k6.io
https://k6.io/docs/using-k6/checks/
Checks
Checks are like asserts but differ in that they do not halt the execution, instead, they just store the result of the check, pass or fail, and let the script execution continue.
k6.io
https://k6.io/docs/test-types/
k6 Documentation
The k6 Documentation helps you to use k6 to get your performance testing on the right track. Learn more about load and performance testing. Get started in minutes.
k6.io
'devops bootcamp 4 > pair/team log' 카테고리의 다른 글
Sprint - 성능 테스트를 위한 서비스 모니터링(advanced) (0) | 2023.06.08 |
---|---|
Sprint - 모니터링 시스템 구축 (0) | 2023.06.05 |
Sprint - Auto Scaling + CloudWatch를 이용한 알림 (0) | 2023.06.02 |
Sprint - 새 버전이 망가졌어요 (0) | 2023.05.19 |
Sprint - Terraform x AWS (0) | 2023.05.17 |