Node.js

NodeJS 환경에서 부하테스트 진행하기(Artillery 이용)

tmkimm 2022. 5. 19. 14:17

사이드 프로젝트에서 프로모션을 준비하고 있는데 갑자기 이런 걱정이 들었습니다.

  • 갑자기 사용자가 몰려서 서버가 터지면 어떡하지?
  • 현재 서버는 몇 명의 사용자까지 감당할 수 있지?

지금까지는 사용자가 몰릴만한 이벤트가 없었기 때문에 문제가 없었지만, 링크 공유로 사용자가 급증하거나 누군가 악의적으로 요청을 많이 보낸다면 서버가 어떻게 될지 모르기 때문에 불안했습니다.

 

찾아보니 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 발음 어떻게 하는 거지..?)

 

 

위 내용은 모두 공식 문서에 있는 내용입니다. 번역기를 돌려도 쉽게 이해할 수 있으니 시간이 된다면 읽어보세요!

 

 

 

 

참고 글