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)
준별
준별
  • 준별
    준별개발
    준별
  • 전체
    오늘
    어제
    • 분류 전체보기 (44)
      • 개발이야기 (12)
        • 토막글 (9)
      • 일상이야기 (5)
      • 개인 공부 (16)
      • 생각과 기록 (2)
  • 블로그 메뉴

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

  • 공지사항

  • 인기 글

  • 태그

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

  • 최근 글

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

티스토리툴바