Artillery와 함께, 웹 부하테스트 빠르게 익히기

2023. 8. 12. 01:57·개발이야기

Artillery.io 로고

Artillery는 Node.js 기반의 API 부하테스트 도구입니다. HTTP 혹은 websocket request를 원하는 시나리오대로 쏴볼수 있습니다. 이를테면, 10분동안 초당 5개의 POST /cat 요청을 쏜다. 같은 상황을 재현할 수 있습니다.

제가 생각하는 Artillery의 장점은 아래와 같습니다.

 

  • 간단한 YAML 파일 작성 만으로도 테스트가 가능
  • 인터페이스도 간단하고 직관적이며, docs도 꽤나 잘 되어 있어서 러닝커브가 적음
  • 테스트 후 보기좋게 시각화된 레포를 제공해줌.

Artillery란?

Artillery 사용법의 핵심이자 전부인 YAML 파일의 샘플을 보겠습니다.

config:
  target: "http://asciiart.artillery.io:8080"
  phases:
    - duration: 60 
      arrivalRate: 5 
scenarios:
  - name: Get 3 animal pictures
    flow:
      - get:
          url: "/dino"
      - get:
          url: "/armadillo"
      - get:
          url: "/pony"

출처) artillery.io 공식 docs

60초 간 초당 5명의 가상 유저(virtual user)가 방문했을 때의 시나리오입니다. 하나의 가상유저는 /dino, /armadillo, /pony 세 요청을 순차적으로 날리게 됩니다. 즉, 이 시나리오에서는 60(초) * 5(회/초) * 3 = 900개의 요청이 날아가게됩니다. 간단하죠?

부하 테스트 시나리오 작성 요령

유의미한 부하테스트 시나리오는 어떻게 작성할 수 있을까요? 이 부분은 이 글에서 발췌했습니다.

  • 부하 테스트 (Load Test)
    • 특정한 부하를 제한된 시간을 두어서 웹 어플리케이션에 이상이 없는지 파악하는 테스트
  • 지속성 테스트 (Endurance Test)
    • Load Test와 유사하나 오랜 기간 부하를 줘서 하는 테스트. Aging 테스트라고 생각하시면 됩니다.
  • 스트레스 테스트 (Stress Test)
    • 부하의 임계점을 찾기 위해 점진적으로 부하를 올리면서 진행하는 테스트
  • 최고 부하 테스트 (Peak Test)
    • 일순간 감당할 수 없을 만큼 부하를 주고, 웹 어플리케이션이 죽지 않고 제대로 동작하고 회복하는지 보는 테스트. 수강신청이나 이벤트 등 대규모 상황을 대비하기 위해 진행

어떤 서버를 테스트하냐에 따라 다르겠으나, 제가 주로 접하게 되는 WAS(Web Application Server)의 경우, 스트레스 테스트와 최고 부하테스트가 유효하게 느껴졌습니다. 시나리오 작성은 아래의 두 지표를 활용했습니다.

 

  • DAU(Daily Active User)
    • 하루에 접속하는 활성 유저를 의미합니다. 하루에 10만명이 접근하는 사이트라면, 30분에는 몇명이 접속할지 대략 가늠할 수 있습니다. 이 엇비슷한 스케일의 숫자로 스트레스 테스트 수치를 잡았습니다.
  • CCU(ConCurrent User)
    • 동시 접속 유저를 의미합니다. 웹 사이트의 링크가 SNS에 공개되는 등 특별한 이벤트가 있을 시, 유저가 특정 시점에 몰려들 수 있습니다. 이 수치를 바탕으로 Peak Test의 수치를 잡았습니다.

Artillery 시나리오 실행하기

artillery run test/stress_test_1.yml #1

artillery run --output stress_test_result.json test/stress_test_1.yml #2
artillery report stress_test_result.json #3

#1:
test/stress_test_1.yml 파일에 작성된 시나리오를 실행합니다.

 

#2:
test/stress_test_1.yml 파일에 작성된 시나리오를 실행하고, 테스트 결과를 stress_test_result.json으로 내보내줍니다.

 

#3:
#2에서 얻은 stress_test_result.json을 통해 HTML 파일을 만들어줍니다. 이 HTML에는 시각화된 테스트 결과 레포트가 담깁니다.

자주 사용하는 YAML 문법

위에 소개했던 YAML 파일을 다시 보겠습니다.

config:
  target: "http://asciiart.artillery.io:8080"
  phases:
    - duration: 60 
      arrivalRate: 5 
scenarios:
  - name: Get 3 animal pictures
    flow:
      - get:
          url: "/dino"
      - get:
          url: "/armadillo"
      - get:
          url: "/pony"

크게 config 파트와 scenarios 파트로 나뉩니다. 두 파트가 각각 무엇을 의미하는지는 짐작이 가실겁니다.

이제 유용하게 사용했던 문법들을 보겠습니다.

초당 N개의 request 쏘기

  phases:
    - duration: 60 # 60초 동안
      arrivalRate: 5 # 초당 5개의 request

쏘는 request 점점 늘리기

  phases:
    - duration: 60 
      arrivalRate: 5 
      rampTo: 10 # 5에서 부터 최대 10req/sec까지 60초 동안 천천히 올라감

N초동안 M개의 request 쏘기

  phases:
    - duration: 60 
      arrivalCount: 5 # 60초 동안 총 100개의 request

response 터미널에 로그로 남기기(response 혹은 그 일부 변수에 담기)

    flow:
      - get:
          url: "/dino"
          url: "/armadillo"
          capture:
          - regexp: "[^]*"     #1
            as: "response" 
       - log: "{{response}}"   #2

#1:
regexp는 정규표현식입니다. "[^]*은 response의 전체를 담는다는 뜻이며, 필요에 맞게 정규표현식을 수정하여 사용하면 매우 편리합니다. 그리고 as라는 필드 다음으로 "response"라는 값을 넘겨주었습니다. 이는 정규표현식으로 capture된 내용을 response에 담겠다는 뜻입니다.

 

#2:
log 필드를 통해 response라는 변수에 담긴 값을 터미널에 그대로 로깅할 수 있습니다.

post 요청 날리기

    flow:
      - post:                            #1
          url: "/dino"                   
          form:                          #2
            ticket_id: "{{ticketId}}"    #3

#1: POST 요청이므로 post

 

#2: form을 사용했습니다. HTTP header에는 application/x-www-form-urlencoded가 심어집니다. 필요에 맞게 json, body 같은 값을 사용해야 하며, 공식 docs를 참고합시다.

 

#3: 앞서 ticketId라는 변수에 값이 담겨 있다면, ticket_id라는 필드에 담아 요청을 보낼 수 있습니다.

유용한 Artillery 사용법

디버깅

모든 요청이 실패하고 있다면, 시나리오를 잘못 작성한 것이겠죠. 이때 아래의 환경 변수를 넘겨주면 어떤 Request를 쏘고 있는지 터미널에 찍히는 로그를 찍어줌으로써 디버깅이 가능합니다.

export DEBUG=http*
# 혹은
export DEBUG=http:response,http:request

그대로 터미널에 복붙해서 사용하세요.

타임아웃 설정

Artillery를 통해 쏜 모든 요청이 errors.ETIMEDOUT와 함께 실패한다면, 타임아웃 시간을 늘릴 필요가 있습니다. 이것은 artillery가 하나의 요청에 대하여 기다려주는 시간제한입니다. 이 시간이 지나면, 아틸러리는 요청을 실패처리하고 더 이상 응답을 기다리지 않습니다.

config:
  http:
    timeout: 60

 

실제 부하테스트 시 겪을 수 있는 문제

  • WAF가 있다면, 모든 요청이 일제히 블락될 수 있습니다. 이때는 WAF를 우회하여 Loadbalancer 혹은 서버 파드에 직접 요청을 쏘는 식으로 진행해야합니다.
  • TLS 관련 문제가 발생하면 이 링크를 참고하세요.
반응형
저작자표시 (새창열림)

'개발이야기' 카테고리의 다른 글

Node.js에서 csv 파일 다루기 및 ios-윈도우 간 한글 깨짐 문제 해결  (1) 2024.01.06
타입스크립트: ts2322 error 해결을 위한 서브타입 관련 개념 총정리  (1) 2023.11.26
한글의 유니코드 인코딩과, javascript에서 한글 문자열을 다루는 방식  (1) 2023.10.19
HTTP의 역사: 0.9부터 3.0까지  (1) 2023.09.14
데코레이터(Decorator)  (1) 2023.09.05
'개발이야기' 카테고리의 다른 글
  • 타입스크립트: ts2322 error 해결을 위한 서브타입 관련 개념 총정리
  • 한글의 유니코드 인코딩과, javascript에서 한글 문자열을 다루는 방식
  • HTTP의 역사: 0.9부터 3.0까지
  • 데코레이터(Decorator)
준별
준별
  • 준별
    준별개발
    준별
  • 전체
    오늘
    어제
    • 분류 전체보기 (50) N
      • 개발이야기 (12)
        • 토막글 (9)
      • 일상이야기 (6) N
      • 개인 공부 (21) N
      • 생각과 기록 (2)
  • 블로그 메뉴

    • 홈
    • 방명록
    • Github
    • Linkedin
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    http1.0
    실전압축
    바이브코딩
    데스크셋업
    맥북터미널세팅
    http3.0
    zsh-autosuggestion
    클램쉘
    persistent connection
    Zsh
    http pipelining
    artillery
    zsh세팅
    필수툴
    맥북
    이산구조
    맥북초기세팅
    k9s
    전산기조직
    터미널세팅
    nodejs
    http1.1
    정보보호개론
    데이터베이스
    nestjs
    맥북세팅
    http2.0
    조합형
    powerlevel10k
    터미널꾸미기
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
준별
Artillery와 함께, 웹 부하테스트 빠르게 익히기
상단으로

티스토리툴바