Artillery로 부하 테스트를 해보자.
ArtilleryVisit Website는 Node.js로 작성된 스트레스 테스트 도구이다.
$ npm i -g artillery
artillery를 먼저 설치해 주자.
{
"config": {
"target": "http://localhost:3000",
"phases": [
{
"duration": 60,
"arrivalRate": 5
}
],
"defaults": {
"headers": {
"Content-Type": "application/json"
}
},
},
"scenarios": [
{
"flow": [
{
"get": {
"url": "/",
"headers": {
"access-token": "{{token}}"
}
}
},
]
}
]
}
json
파일으로 테스트 내용을 작성해주면 된다. yml
파일로 작성할 수 도 있지만 json파일이 더 친숙하기 때문에 json파일로 작성하였다.
phases": [
{
"duration": 60,
"arrivalRate": 5
}
]
phaese
부분에는 몇초동안 몇번씩 실행할지 작성해줄 수 있는데, 위의 옵션은 60초 동안 초당 5번씩 scenarios
에 있는 flows
들을 실행한다는 뜻이다. 위에는 flow에 get /
만 적혀있어 초당 5번만 실행되지만 10개를 작성하면 초당 50개씩 요청이 간다.
$ artillery ./test/stress.test.config.yml
해당 명령어를 터미널에 작성하면 파일에 작성한대로 테스트가 실행된다.
{
"get": {
"url": "/users/me",
"headers": {
"access-token": "asdiofnasifnjaweklfn..."
}
}
},
우리 서비스는 모든 요청에 헤더에 토큰이 필요해서 이렇게 요청마다 넣어주어야 한다. 하지만 이건 너무 번거롭다. 또한 하나의 토큰만 사용하여 하나의 유저에 대해 테스트하는 것도 테스트의 의미가 사라진다고 생각한다.
usertoken-1
usertoken-2
usertoken-3
usertoken-4
usertoken-5
.
.
.
이렇게 csv파일에 각기 다른 유저의 토큰을 넣어주고
{
"config": {
"target": "http://localhost:3000",
"phases": [
{
"duration": 60,
"arrivalRate": 5
}
],
"defaults": {
"headers": {
"Content-Type": "application/json"
}
},
"payload": {
"path": "./tokens.csv",
"fields": ["token"]
}
},
...
그리고 payload
에서 csv파일을 import해준다. 그 다음 field
에서 csv에 설정한 변수를 가져와준다.
{
"get": {
"url": "/users/me",
"headers": {
"access-token": {{token}}
}
}
},
이제 header에 토큰을 넣어주면 여러유저의 토큰이 돌아가면서 사용될 것이다.
"scenarios": [
{
"flow": [
{
"get": {
"url": "/",
"headers": {
"access-token": "{{token}}"
}
}
},
{
"get": {
"url": "/users/me",
"headers": {
"access-token": "{{token}}"
}
}
},
...
그리고 모든 get
요청에 대해 시나리오를 작성해 주었다. (우리 서비스가 조회가 많이 일어나는 서비스이기 때문)
"phases": [
{
"duration": 60,
"arrivalRate": 5
}
],
먼저 초당 50번의 요청을 보내보자 (arrivalRate
가 5이지만 flow가 10개이므로)
http.requests
가 요청을 보낸 총 횟수이고
mean
은 평균적 속도
p95
는 예를 들어, P95 응답 시간이 50ms라면 이는 전체 요청 중 95%의 경우가 50ms 이하로 처리된다는 것을 의미한다. 5%의 경우는 50ms를 초과하여 처리된다.
P99
응답 시간이 100ms라면 이는 전체 요청 중 99%의 경우가 100ms 이하로 처리된다는 것을 의미한다. 1%의 경우는 100ms를 초과하여 처리된다.
P99와 P95는 평균(mean)보다 이상치(outlier)에 덜 민감하며, 전체 데이터 분포를 더 잘 반영한다.
결과를 보면 어쨋든 초당 50회 요청까지는 매우 빠르게 응답을 하는 것으로 확인할 수 있다.
"phases": [
{
"duration": 60,
"arrivalRate": 100
}
],
그 다음 초당 100회 요청을 보내보자.
50회보단 느리지만 p95
가 198.4ms인것을 보니 아직까지는 매우 빠르게 응답하는 것을 확인할 수 있다.
200번 요청부턴 응답 시간이 기하급수적으로 늘었다. 50회일때는 p95
가 198.4m였는데 초당 요청량을 2배로 늘렸더니 p95
가 8000ms 거의 40배 가량 늘어버렸다.
이로인해 초당 200번 요청부터는 서버가 버티지 못하는 것을 깨달았다.
artillery run --output result.json ./test/stress.test.config.yml
artillery로 실행시에 --output
option을 넣어주면 해당 스크린샷에 나온 값을을 json파일로 저장할 수 있다.
npx artillery report result.json
그리고 report
명령어를 사용하면 해당 json파일을 그래프로 시각화하여 볼 수 있다.
해당 명령어를 작성하면 html파일이 생성되는데, html파일을 열어보면 위 처럼 여러 지표들을 그래프로 시각화하여 볼 수 있다.