Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[김대겸] Step2 PR #569

Merged
merged 2 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
70 changes: 70 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,78 @@ npm run dev
### 2단계 - 부하 테스트
1. 부하테스트 전제조건은 어느정도로 설정하셨나요

- [X] 대상 시스템 범위
- WEB → WAS → DB
- [X] 목푯값 설정 (latency, throughput, 부하 유지기간)
- latency : 100ms
- throughput
- 집중률 = 최대트래픽 / 평소트래픽 = 5.00 (5배 가정)
- 예상 1일 사용자 수(DAU): 100,000명 가정
- 1명당 1일 평균 접속 수 = 5
- 메인 페이지 ➝ 로그인 -> 내 정보 요청 -> 경로 검색 페이지 -> 경로 검색
- 1일 총 접속 수 = DAU(100,000) * 1명당 1일 평균 접속 수(5) = 500,000
- 1일 평균 rps = 1일 총 접속 수(500,000) / 1일 초단위 시간(86400) = 5.78 rps
- 1일 최대 rps = 5.78 * 피크 시간대의 집중률(5.00) = 28.9 rps
- 부하 유지기간
- Smoke: 1m
- Load: 30m
- Stress: 30m
- [X] 부하 테스트 시 저장될 데이터 건수 및 크기
- 데이터 조회 테스트이기 때문에 저장될 데이터 없음

### VUser 구하는 공식 이해하기
- Request Rate: measured by the number of requests per second (RPS)
- 요청 속도: 초당 요청 수로 측정됨
- VU: the number of virtual users
- 가상 사용자 수
- R: the number of requests per VU iteration
- VU 반복당 요청 수
- T: a value larger than the time needed to complete a VU iteration
- VU 반복을 완료하는 데 필요한 시간

```
T = (R * http_req_duration) (+ 1s) ; 내부망에서 테스트할 경우 예상 latency를 추가한다
VUser = (목표 rps * T) / R
```
- VU 반복을 완료하는 데 필요한 시간 = (VU 반복당 요청 수 x http 요청지속시간) + Latency
- 가상 사용자 수 = (목표 RPS * VU 반복을 완료하는 데 필요한 시간) / 요청 개수
- 목표 RPS = (가상 사용자 수 * 요청 개수) / VU 반복을 완료하는 데 필요한 시간


### 목표 / 평균 VUser 값 구하기
- R = 5
- T = (5 * 0.1s) + 1s = 1.5s
- 평균 VUser = (5.78 * 1.5s) / 5 = 1.734 (2명)
- 목표 VUser = (28.9 * 1.5s) / 5 = 8.67 (9명)


2. Smoke, Load, Stress 테스트 스크립트와 결과를 공유해주세요

- smoke
- smoke.js
- smoke_grafana.png
- smoke_k6.png
- load
- load.js
- load_grafana.png
- load_k6.png
- stress
- stress.js
- stress_grafana.png
- stress_k6.png

#### 요구사항 체크리스트
- [X] 부하 테스트
- [X] 테스트 전제조건 정리
- [X] 대상 시스템 범위
- [X] 목푯값 설정 (latency, throughput, 부하 유지기간)
- [X] 부하 테스트 시 저장될 데이터 건수 및 크기
- [X] 아래 시나리오 중 하나를 선택하여 스크립트 작성
- [X] 접속 빈도가 높은 페이지
- [ ] 데이터를 갱신하는 페이지
- [ ] 데이터를 조회하는데 여러 데이터를 참조하는 페이지
- [X] Smoke, Load, Stress 테스트 후 결과를 기록

---

### 3단계 - 로깅, 모니터링
Expand Down
87 changes: 87 additions & 0 deletions monitoring/load/load.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import http from 'k6/http';
import { check, group, sleep, fail } from 'k6';

export let options = {
stages: [
{ duration: '30s', target: 5 },
{ duration: '5m', target: 6 },
{ duration: '4m', target: 7 },
{ duration: '20s', target: 9 },
{ duration: '5m', target: 9 },
{ duration: '10s', target: 7 },
{ duration: '10m', target: 6 },
{ duration: '5m', target: 0 },
],
thresholds: {
http_req_duration: ['p(99)<100'],
},
};

const BASE_URL = 'https://gyeom-subway-admin.kro.kr/';
const USERNAME = 'koreatech93@naver.com';
const PASSWORD = 'tkatkatka05)%';


export default function () {
mainPage();
const authHeaders = login();
retrieveMember(authHeaders);
pathPage();
findPath(authHeaders);

sleep(1);
}
Comment on lines +25 to +33

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트 시나리오 잘 작성해주셨네요 👍🏻



function mainPage() {
const response = http.get(BASE_URL);

check(response, {
'entered in main page successfully': (res) => res.status === 200
});
}

function login() {
const payload = JSON.stringify({
email: USERNAME,
password: PASSWORD,
});
const params = {
headers: {
'Content-Type': 'application/json',
},
};

const response = http.post(`${BASE_URL}/login/token`, payload, params);

check(response, {
'logged in successfully': (res) => res.json('accessToken') !== '',
});

return {
headers: {
Authorization: `Bearer ${response.json('accessToken')}`,
},
};
}

function retrieveMember(authHeaders) {
let myObjects = http.get(`${BASE_URL}/members/me`, authHeaders).json();
check(myObjects, { 'retrieved member': (obj) => obj.id != 0 });
}

function pathPage() {
const response = http.get(`${BASE_URL}/path`);

check(response, {
'entered in path page successfully': (res) => res.status === 200
});
}

function findPath(authHeaders) {
const response = http.get(`${BASE_URL}/path?source=3&target=4`, authHeaders);

check(response, {
'get path info successfully': (res) => res.status === 200
});
}
Binary file added monitoring/load/load_grafana.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added monitoring/load/load_k6.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
80 changes: 80 additions & 0 deletions monitoring/smoke/smoke.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import http from 'k6/http';
import { check, group, sleep, fail } from 'k6';

export let options = {
vus: 1,
duration: '1m',

thresholds: {
http_req_duration: ['p(99)<100'], // 99% of requests must complete below 0.1s
},
};

const BASE_URL = 'https://gyeom-subway-admin.kro.kr/';
const USERNAME = 'koreatech93@naver.com';
const PASSWORD = 'tkatkatka05)%';


export default function () {
mainPage();
const authHeaders = login();
retrieveMember(authHeaders);
pathPage();
findPath(authHeaders);

sleep(1);
}


function mainPage() {
const response = http.get(BASE_URL);

check(response, {
'entered in main page successfully': (res) => res.status === 200
});
}

function login() {
const payload = JSON.stringify({
email: USERNAME,
password: PASSWORD,
});
const params = {
headers: {
'Content-Type': 'application/json',
},
};

const response = http.post(`${BASE_URL}/login/token`, payload, params);

check(response, {
'logged in successfully': (res) => res.json('accessToken') !== '',
});

return {
headers: {
Authorization: `Bearer ${response.json('accessToken')}`,
},
};
}

function retrieveMember(authHeaders) {
let myObjects = http.get(`${BASE_URL}/members/me`, authHeaders).json();
check(myObjects, { 'retrieved member': (obj) => obj.id != 0 });
}

function pathPage() {
const response = http.get(`${BASE_URL}/path`);

check(response, {
'entered in path page successfully': (res) => res.status === 200
});
}

function findPath(authHeaders) {
const response = http.get(`${BASE_URL}/path?source=3&target=4`, authHeaders);

check(response, {
'get path info successfully': (res) => res.status === 200
});
}
Binary file added monitoring/smoke/smoke_grafana.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added monitoring/smoke/smoke_k6.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
95 changes: 95 additions & 0 deletions monitoring/stress/stress.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import http from 'k6/http';
import { check, group, sleep, fail } from 'k6';

export let options = {
stages: [
{ duration: '2m', target: 0 },
{ duration: '2m', target: 5 },
{ duration: '2m', target: 10 },
{ duration: '2m', target: 20 },
{ duration: '2m', target: 40 },
{ duration: '2m', target: 80 },
{ duration: '2m', target: 160 },
{ duration: '2m', target: 320 },
{ duration: '2m', target: 160 },
{ duration: '2m', target: 80 },
{ duration: '2m', target: 40 },
{ duration: '2m', target: 20 },
{ duration: '2m', target: 10 },
{ duration: '2m', target: 5 },
{ duration: '2m', target: 0 }, // ramp-down to 0 users
],
thresholds: {
http_req_duration: ['p(99)<100'],
},
};


const BASE_URL = 'https://gyeom-subway-admin.kro.kr/';
const USERNAME = 'koreatech93@naver.com';
const PASSWORD = 'tkatkatka05)%';


export default function () {
mainPage();
const authHeaders = login();
retrieveMember(authHeaders);
pathPage();
findPath(authHeaders);

sleep(1);
}


function mainPage() {
const response = http.get(BASE_URL);

check(response, {
'entered in main page successfully': (res) => res.status === 200
});
}

function login() {
const payload = JSON.stringify({
email: USERNAME,
password: PASSWORD,
});
const params = {
headers: {
'Content-Type': 'application/json',
},
};

const response = http.post(`${BASE_URL}/login/token`, payload, params);

check(response, {
'logged in successfully': (res) => res.json('accessToken') !== '',
});

return {
headers: {
Authorization: `Bearer ${response.json('accessToken')}`,
},
};
}

function retrieveMember(authHeaders) {
let myObjects = http.get(`${BASE_URL}/members/me`, authHeaders).json();
check(myObjects, { 'retrieved member': (obj) => obj.id != 0 });
}

function pathPage() {
const response = http.get(`${BASE_URL}/path`);

check(response, {
'entered in path page successfully': (res) => res.status === 200
});
}

function findPath(authHeaders) {
const response = http.get(`${BASE_URL}/path?source=3&target=4`, authHeaders);

check(response, {
'get path info successfully': (res) => res.status === 200
});
}
Binary file added monitoring/stress/stress_grafana.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added monitoring/stress/stress_k6.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.