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/
https://k6.io/docs/using-k6/checks/
https://k6.io/docs/test-types/
'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 |