사이드 프로젝트에서 프로모션을 준비하고 있는데 갑자기 이런 걱정이 들었습니다.
- 갑자기 사용자가 몰려서 서버가 터지면 어떡하지?
- 현재 서버는 몇 명의 사용자까지 감당할 수 있지?
지금까지는 사용자가 몰릴만한 이벤트가 없었기 때문에 문제가 없었지만, 링크 공유로 사용자가 급증하거나 누군가 악의적으로 요청을 많이 보낸다면 서버가 어떻게 될지 모르기 때문에 불안했습니다.
찾아보니 NodeJs로 쉽게 부하테스트를 진행할 수 있는 Artillery라는 툴이 있었고 덕분에 서버의 한계치를 알 수 있었습니다 :)
처음 진행한 부하 테스트이다보니 부족한 내용이 있다면 댓글 달아주시면 감사하겠습니다. 🙏
부하테스트란?
임계치의 한계에 도달할 때까지 시스템에 부하를 꾸준히 증가시키며 진행하는 테스트
성능 테스트, 스트레스 테스트, 부하 테스트는 다른 것이므로 명칭을 명확하게 하는 게 좋습니다.
성능, 부하, 스트레스 테스트를 진행하고 튜닝하는 작업에는 굉장히 오랜 시간과 노력이 필요합니다.
부하 테스트 어떻게 하는 거지?
실제 서비스에 부하 테스트를 하기보단 실제 서버와 같은 사양의 서버(이를 보통 staging 서버라고 부름) 를 만든 후에 그 서버에 부하 테스트를 진행하는 것이 좋습니다.
저도 실제 서비스에 아무런 영향이 없도록 새로운 AWS EC2와 mongoDB Atlas를 만들어서 진행하였습니다.
요청을 보낼 서버가 준비됐다면 부하 테스트 시나리오를 작성하면 됩니다.
- 사용자가 서비스에 접속했을 때 어떤 순서로 API를 요청하는지
- 보통 몇 초 주기로 API를 요청하는지
- 몇 명의 사용자까지 버티는 것을 목표로 할 것 인지
Artillery 맛보기
artillery 사용 방법은 정말 간단합니다. 쉽게 2번의 명령어로 테스트를 해볼 수 있습니다.
artillery를 설치하고
npm run artillery -g
quick 명령어를 이용하여 부하 테스트를 진행합니다.
artillery quick --duration 60 --rate 10 -n 5 http://localhost:5000
위 명령어를 해석해보면 http://localhost:5000로 60초 동안 5명이 초당 10번의 요청을 보내게 됩니다.
60 * 5 * 10 = 3,000번의 요청을 보내게 되는 것이죠.
duration : 지속할 시간
rate : 요청 수
n : 요청자 수
테스트가 끝나면 아래 사진처럼 그 결과를 출력해줍니다.
단위는 ms(millisecond)이며 총 요청 수, 평균 응답 시간, HTTP STATUS별 응답 수 등을 표시해줍니다.
- http.codes.200 : 200번으로 응답이 온 요청 수
- http.requests : 총 요청 수
- http.response_time : 응답 시간
- min : 최소 응답 시간
- max : 최대 응답 시간
- median : 평균 응답 시간
- p95 : 느린 요청 중 95%의 응답 시간
- p99 : 느린 요청 중 99%의 응답 시간
공식 문서를 보면 quick에 대한 더 자세한 내용을 확인할 수 있습니다.
Artillery 제대로 사용하기
run 명령을 이용하면 실제 사용자가 서비스를 이용하는 것과 동일하게 시나리오대로 부하 테스트를 진행할 수 있습니다.
먼저 scenarios.yaml 파일을 만들고 아래와 같이 작성합니다.
phases에서는 부하 테스트에 대한 단계를 지정합니다.
첫 번째 단계는 Warm up으로 60초 동안 1초마다 5명의 사용자가 요청을 하고
두 번째 단계는 5명의 가상 사용자로 시작하여 점점 증가하고, 120초 동안 요청을 보내며 최대 사용자는 50명으로 지정합니다.
config:
target: "https://example.com/api"
phases:
- duration: 60
arrivalRate: 5
name: Warm up
- duration: 120
arrivalRate: 5
rampTo: 50
name: Ramp up load
그다음은 scenarios를 이용하여 요청에 대한 시나리오를 작성합니다.
사용자는 post 요청을 보낸 후 get 요청을 보내게 됩니다.
scenarios:
- name: "Search and buy"
flow:
- post:
url: "/search"
json:
kw: "{{ keyword }}"
capture:
- json: "$.results[0].id"
as: "productId"
- get:
url: "/product/{{ productId }}/details"
완성된 파일은 아래와 같습니다.
config:
target: "https://example.com/api"
phases:
- duration: 60
arrivalRate: 5
name: Warm up
- duration: 120
arrivalRate: 5
rampTo: 50
name: Ramp up load
payload:
path: "keywords.csv"
fields:
- "keyword"
scenarios:
- name: "Search and buy"
flow:
- post:
url: "/search"
json:
kw: "{{ keyword }}"
capture:
- json: "$.results[0].id"
as: "productId"
- get:
url: "/product/{{ productId }}/details"
npx artillery run artillery/scenarios.yaml 명령을 통해 부하 테스트를 실행하면 quick과 마찬가지로 테스트를 진행하고 그 결과를 출력해줍니다. 👍👍
인증/인가 시 Access Token을 사용하여 auth headers를 지정해주고 싶은 경우 아래처럼 작성하면 됩니다.
scenarios:
- flow:
- get:
url: "/data"
headers:
authorization: "Bearer {token}"
Conclusion
저는 Artillery를 이용해서 쉽게 부하 테스트를 진행할 수 있었고 막연한 불안감도 어느 정도 해소되었습니다.
같은 불안함을 갖고 계신 분들이라면 꼭 한번 진행해보는 것을 추천드립니다.
(Artillery 발음 어떻게 하는 거지..?)
위 내용은 모두 공식 문서에 있는 내용입니다. 번역기를 돌려도 쉽게 이해할 수 있으니 시간이 된다면 읽어보세요!
참고 글
'Node.js' 카테고리의 다른 글
nodeJS(typescript)에 swagger 적용하기 (0) | 2022.11.04 |
---|---|
swagger로 API 문서 자동화하기(nodeJS) (0) | 2022.11.01 |
Node.js란? Node.js 특징 정리(이벤트 기반, 논 블로킹 I/O 모델) (1) | 2021.11.19 |
Node.js(express) 프로젝트 설계하기 (8) | 2021.08.31 |
[Node.js] __dirname is not defined 에러 (0) | 2021.01.27 |