본문 바로가기
Research/Testing

Artillery로 성능 측정하기

by RIEM 2023. 2. 22.

배경

스트레스 테스트 도구 왜 사용하나?

  • API 서버, 웹 어플리케이션 서버를 만든 뒤 성능 테스트를 하기 위해
  • 한 마디로, 서버가 얼마만큼의 요청을 견디는가?

이점

  • 병목 지점을 찾을 수 있다
  • 사용자 증가에 따라 언제즈음 서버를 늘릴 수 있는지에 대한 트래픽 기준을 얻을 수 있다
  • 동시 접속사, 일일 사용자의 한계치를 예측할 수 있다
  • OOM(out of memory) 문제 방지. 코드에 문법적, 논리적 문제가 없어도 하드웨어 제약 때문에 서비스가 중단되는 문제를 사전에 예방하는데 도움이 된다

도구 종류

  • ab
  • Artillery
  • nGrinder
  • Gatling
  • Tsung
  • JMeter

nodejs에서 가볍게 쓰려면 Artillery, 정교하게 측정하려면 nGrinder, JMeter 등을 사용

Artillery란?

  • Node.js로 작성된 스트레스 테스트 도구

Artillery의 특징

  • HTTPS, Socket.io, Websocket 등 다양한 프로토콜 지원
  • 시나리오 테스트 가능
  • JS로 로직 작성 가능
  • statsd 지원. Datadog나 InfluxDB 등에 실시간으로 결과 등록 가능
  • 리포트 페이지 제공

구현

Node.js 설치

생략

Artillery 설치

https://www.artillery.io/docs/guides/getting-started/installing-artillery

npm install -g artillery@latest
npm i -D artillery

전역 설치가 싫다면..

간단 테스트

요청

quick 명령어로 가볍게 테스트해볼 수 있다.

 npx artillery quick --count 100 -n 50 http://localhost:3000/raffles/478 

localhost에 100명의 가상 유저가 50회씩 요청하도록 해줘(총 5000회 요청)

  • --count : 가상 사용자 수
  • -n : 요청 횟수
  • --rate : 초당 요청

결과

...

Summary report @ 18:22:39(+0900)

http.codes.200: ................................................................ 5000
http.request_rate: ............................................................. 206/sec
http.requests: ................................................................. 5000
http.response_time:
min: ......................................................................... 39
max: ......................................................................... 928
median: ...................................................................... 468.8
p95: ......................................................................... 584.2
p99: ......................................................................... 804.5
http.responses: ................................................................ 5000
vusers.completed: .............................................................. 100
vusers.created: ................................................................ 100
vusers.created_by_name.0: ...................................................... 100
vusers.failed: ................................................................. 0
vusers.session_length:
min: ......................................................................... 22111.6
max: ......................................................................... 23770.2
median: ...................................................................... 23630.3
p95: ......................................................................... 23630.3
p99: ......................................................................... 23630.3


vusers.completed:  100  -> 100명의 가장 유저의 수행이 모두 성공
vusers.created:  100
vusers.created_by_name.0:  100
vusers.failed:  0  -> 실패는 0개
http.codes.200:  5000
http.request_rate:  206/sec
http.requests:  5000  -> 5000회 요청
http.response_time:
  min:  39  -> 가장 빠른 것이 0.039 sec
  max:  928  -> 가장 느린 건 0.928 sec
  median:  468.8  -> 중간 값 0.468 sec
  p95:  584.2  -> 뒤에서 6번째(95번째)로 느린 사람이 0.584 sec
  p99:  804.5  -> 뒤에서 2번째(99번째)로 느린 사람이 0.804 sec

p95, p99 차이가 낮으면 성능이 좋다는 의미라 한다. 왜냐하면 편차가 낮을 수록 비슷한 속도로 처리되었다는 의미이기 때문이다.

주의

  • 실제 서비스 중인 서버에 테스트할 경우 중단될 수 있고
  • AWS, GCP 클라우드의 종량제 요금 사용중일 경우, 요금 과다 청구 발생 할 수 있다
    locallhost에서는 스트레스 테스트를 하더라도 큰 문제가 없다

해결 방법

  • 실제 서비스에 부하 테스트하지 말고
  • 실제 서버와 같은 사양의 서버(staging 서버)를 만들어서 그 서버에 부하 테스트를 진행하는 것이 좋다

상세 테스트

Artillery 스크립트 작성

스크립트 양식

  • JSON
  • YAML

요소

  • target : 인스턴스로 접속할 url
  • duration : 성능 측정 시간
  • arrivalRate : 매초마다 새 가상 유저가 생성되는가

시나리오 설정 파일 옵션

"config" 영역

  • target : 테스트 할 앱의 url. 서버 주소
  • phases: 테스트 요청 시간과 비율. {"duration": 60, "arrivalRate": 30}은 60초 동안 매초 30개의 요청을 보내주세요라는 의미
  • defaults : 뒤에서 테스트할 시나리오의 기본값 설정
  • payload : 임의 데이터 보내기 위해 사용. csv 파일로 실제 데이터를 전송하도록 할 수도 있음
  • socketio : 소켓 테스트 가능하다.
    • query : socket들이 들어오는 주소 끝에 roomID로 쿼리를 다고 있기에, 이 쿼리 부분을 작성해주는 것. 방 생성 시 roomID가 달라져서 이 부분을 바꿔주는 것이 번거로울 수 있음
  • plugins : 플러그인 설정. tls: configure how Artillery handles self-signed certificates
  • ensure : 에러나 지연시간에 대해 성공 조건 세팅
  • processor : 커스텀 js 코드 load

"Scenario" 영역

  • name : 시나리오 명
  • flow : 시나리오에서 진행하는 테스트 동작 순서대로 작성
  • capture : 응답으로 받은 데이터를 변수에 저장하는 기능. 추후 다른 요청에서 사용할 수 있다
  • match : 응답 데이터가 원하는 값이 오는지 확인 가능
  • weight : 시나리오에 대한 가중치. 이 값이 높으면 해당 시나리오가 더 많이 발생

실제 코드

loadtest.json

{
   "config": {
      "target": "http://localhost:8001",
      "phases": [
         {
            "duration": 60,
            "arrivalRate": 30
         }
      ]
   },
   "scenarios": [
      {
         "flow": [
            {
               "get": {
                  "url": "/"
               }
            },
            {
               "post": {
                  "url": "/auth/login",
                  "json": {
                     "email": "test1@test.com",
                     "password": "123123"
                  }
               }
            },
            {
               "get": {
                  "url": "/hashtag?hashtag=test"
               }
            }
         ]
      }
   ]
}

나는 GET요청만 테스트하고 싶기에 이렇게 수정했다.

{
  "config": {
    "target": "http://localhost:3000",
    "phases": [
      {
        "duration": 60,
        "arrivalRate": 100
      }
    ]
  },
  "scenarios": [
    {
      "flow": [
        {"get": {
          "url": "/raffles/478"
        }}
      ]
    }
  ]
}

Reference

댓글