이 연재글은 웹 애플리케이션 부하 테스트 실습의 3번째 글입니다.

Taurus

타우르스는 애플리케이션 부하 테스트를 자동화 하는데 도움을 주는 오픈소스 프레임워크 입니다. 다양한 executor(jmeter, selenium, gatling, junit 등등)를 지원하며 각자의 환경과 시나리오에 적합한 executor를 자유롭게 선택하여 사용할 수 있습니다.(https://gettaurus.org/docs/ExecutionSettings/) docker를 지원하여 쉽고 빠르게 테스팅 환경을 구성할 수 있으며 테스트 결과 Metric을 Blazemeter와 연동하여 멋진 보고서도 제공 받을 수 있습니다.

https://gettaurus.org/

테스트 환경 구성

docker를 이용하여 테스트를 수행하므로 docker를 사용할 수 있는 환경이라면 어디서든 부하 테스트가 가능합니다. 실습에서는 mac 환경에서 테스트를 수행하였습니다. 아래와 같이 테스트를 진행할 작업 디렉터리를 생성하고 하위에 docker-compose.yml을 생성 합니다. 서버에서 실행할 경우 docker-compose내의 volumes directory를 환경에 맞게 수정하여 사용하면 됩니다.

작업 디렉터리 생성

artifacts – 테스트에 의해 런타임에 생성되는 파일(로그, 테스트결과 등..)이 위치하는 디렉터리 입니다.
script – 테스트 시나리오가 위치하는 디렉터리 입니다.

./taurus
├── artifacts
├── docker-compose.yml
└── script

docker-compose.yml 생성

version: '3.7'

services:
  taurus:                         # service name
    image: blazemeter/taurus      # image 설정
    # network_mode: host
    ulimits:                      # 프로세스의 자원 한도를 설정
      nproc: 65535                # User당 사용할 수 있는 프로세스 최대 개수
      nofile:                     # User당 오픈할 수 있는 파일 개수
        soft: 90000               # soft 설정
        hard: 90000               # hard 설정
    sysctls:
      net.ipv4.ip_local_port_range: 1025 65000    # port 범위 설정
    volumes:
      - /Users/happydaddy/taurus/script:/bzt-configs       # bizt-configs 볼륨 설정
      - /Users/happydaddy/taurus/artifacts:/tmp/artifacts  # artifacts 볼륨 설정 (테스트 로그 및 결과)

테스트 시나리오 작성

script 디렉터리 하위에 테스트 시나리오를 작성합니다.

execution:
- concurrency: 10
  ramp-up: 1m
  hold-for: 1m
  scenario: quick-test

scenarios:
  quick-test:
    requests:
    - http://blazedemo.com

테스트 실행

docker-compose를 실행하면 taurus docker 환경이 자동으로 구성되며 sample-test.yml에 작성한 시나리오가 실행됩니다. -report 인자를 추가하면 테스트 완료 후에 blazemeter로 metric을 전송하여 웹 보고서를 생성 할 수 있습니다.

$ docker-compose run --rm taurus sample-test.yml -report
Creating network "taurus2_default" with the default driver
Creating taurus2_taurus_run ... done
11:04:03 INFO: Taurus CLI Tool v1.15.3
11:04:03 INFO: Starting with configs: ['sample-test.yml']
11:04:03 INFO: Configuring...
11:04:03 INFO: Artifacts dir: /tmp/artifacts
11:04:03 INFO: Preparing...
11:04:12 INFO: Waiting for finish...r updates
11:04:21 INFO: Changed data analysis delay to 5s, will upload anonymously
11:04:39 INFO: Changed data analysis delay to 4s
11:04:40 INFO: Changed data analysis delay to 5s
11:04:47 INFO: Changed data analysis delay to 4s
11:06:17 WARNING: Please wait for graceful shutdown...ter.com/app/?public-token=BV7LKqoYmNaMlu7GRTNmz7ggKxSW5M9msegKtxi7MPR43u2xnm#reports/r-ext-6194e1abbf84d654189135/11:06:17 INFO: Shutting down...
11:06:17 INFO: Post-processing... in browser: could not locate runnable browser
11:06:17 INFO: Test duration: 0:02:06
11:06:17 INFO: Samples count: 546, 0.00% failures
11:06:17 INFO: Average times: total 1.669, latency 0.297, connect 0.036
11:06:17 INFO: Percentiles:
┌───────────────┬───────────────┐
│ Percentile, % │ Resp. Time, s │
├───────────────┼───────────────┤
│           0.0 │         1.387 │
│          50.0 │         1.661 │
│          90.0 │         1.847 │
│          95.0 │         1.948 │
│          99.0 │           2.1 │
│          99.9 │         2.382 │
│         100.0 │         2.382 │
└───────────────┴───────────────┘
11:06:17 INFO: Request label stats:
┌──────────────────────┬────────┬─────────┬────────┬───────┐
│ label                │ status │    succ │ avg_rt │ error │
├──────────────────────┼────────┼─────────┼────────┼───────┤
│ http://blazedemo.com │   OK   │ 100.00% │  1.669 │       │
└──────────────────────┴────────┴─────────┴────────┴───────┘
11:06:17 INFO: Sending remaining KPI data to server...
11:06:18 INFO: Ending data feeding...
11:06:19 INFO: Online report link: https://a.blazemeter.com/app/?public-token=BV7LKqoYmNaMlu7GRTNmz7ggKxSW5M9msegKtxi7MPR43u2xnm#reports/r-ext-6194e1abbf84d654189135/summary
11:06:19 INFO: Artifacts dir: /tmp/artifacts
11:06:19 INFO: Done performing with code: 0

테스트 결과 확인

console log에 간략하게 테스트 결과가 표시됩니다. artifacts 디렉터리 하위에는 테스트 결과물이 생성되므로 필요한 내용을 열어서 확인할 수 있습니다.

$ cd artifacts
$ ls -lt | more
total 328
-rw-r--r--  1 happydaddy  staff  30554 11 17 20:06 bzt.log
-rw-r--r--  1 happydaddy  staff   6256 11 17 20:06 effective.json
-rw-r--r--  1 happydaddy  staff   5053 11 17 20:06 effective.yml
-rw-r--r--  1 happydaddy  staff   9347 11 17 20:06 jmeter.log
-rw-r--r--  1 happydaddy  staff    308 11 17 20:06 jmeter.out
-rw-r--r--  1 happydaddy  staff     83 11 17 20:06 error.jtl
-rw-r--r--  1 happydaddy  staff  62066 11 17 20:06 kpi.jtl
-rw-r--r--  1 happydaddy  staff      0 11 17 20:04 jmeter.err
-rw-r--r--  1 happydaddy  staff   6023 11 17 20:04 modified_requests.jmx
-rw-r--r--  1 happydaddy  staff    322 11 17 20:04 jmeter-bzt.properties
-rw-r--r--  1 happydaddy  staff     23 11 17 20:04 system.properties
-rw-r--r--  1 happydaddy  staff   4056 11 17 20:04 requests.jmx
-rw-r--r--  1 happydaddy  staff    148 11 17 20:04 sample-test.yml
-rw-r--r--  1 happydaddy  staff    213 11 17 20:04 merged.json
-rw-r--r--  1 happydaddy  staff    152 11 17 20:04 merged.yml

BlazeMeter Report

console에 출력된 Online report link를 브라우저에서 실행하면 상세한 내용을 담고 있는 blazemeter 보고서를 확인 할 수 있습니다. blazemeter url은 일정기간만 유지되므로 필요한 데이터는 백업해 두도록 합니다.
Online report link: https://a.blazemeter.com/app/?public-token=BV7LKqoYmNaMlu7GRTNmz7ggKxSW5M9msegKtxi7MPR43u2xnm#reports/r-ext-6194e1abbf84d654189135/summary

테스트 환경 구성과 테스트 실행 그리고 보고서 작성까지 taurus를 사용하면 정말 빠르고 간단하게 부하 테스트를 수행할 수 있습니다. 개발자는 테스트 시나리오 작성에만 신경을 쓰고 집중할 수 있게 됩니다.

Taurus Script 작성

실습에서는 yaml을 이용하여 test script를 작성하는 방법에 대해서 간략히 알아보겠습니다.

https://gettaurus.org/docs/ExecutionSettings/

Execution

테스트 시나리오 실행 방법을 정의합니다.

  • concurrency: 동시 사용자 수
  • ramp-up: concurrency 설정에 도달하는 시간
  • hold-for: 동시 사용자 수 유지 시간
  • throughput: 처리량 제한

example

총 테스트시간 : 대략 3분30초 = ramp-up(1분) + hold-for(2분30초)
ramp-up 시간 : 1분 동안 사용자 수를 concurrency 10까지 증가시킨다.
hold-for 시간 : 설정한 concurrency 수까지 되면 2분 30초간 테스트를 유지한다.

execution:
- concurrency: 10
  hold-for: 2m30s
  ramp-up: 1m
  scenario:
    requests:
       - url: http://blazedemo.com/

10명의 가상 사용자는 초당 40개 미만의 요청을 제공합니다

throughput 설정 추가하면 초당 요청 속도를 제한 할 수 있습니다.

execution:
- concurrency: 10
  hold-for: 2m30s
  ramp-up: 1m
  throughput: 5
  scenario:
    requests:
       - url: http://blazedemo.com/
  1. 60초에 걸쳐 부하를 1에서 5 RPS로 증가(램프 업)
  2. 150초 동안 5RPS로 하중 유지(hold-for)

Scenarioes 구성

여러개의 시나리오를 구성하여 수행할 수 있습니다. Data-Source 설정으로 동적 데이터를 설정할 수 있습니다.

input-data.csv

컴마(,)로 구분된 데이터 셋을 준비합니다.

40,-EPISODE_UPDATE,appId-1,Z2luU3RhdHVzIjoiQUNUSVZFIn0.cV4Nn7HAZyZE1CtaWvSQQObed4EbGXAKbdOWC0-2Gfc
31,-CONTENT_SUBSCRIBE,appId-2,jAuMSIsImxvZ2luU3RhdHIn0.RqFDk-5DhmnZqQ8SfQBW1cpWsmFdh1fu84ZUizouLLo
31,-CONTENT_SUBSCRIBE,appId-3,OTIuMTY4LjAuMSIsISVZFIn0.TkKl12UsSZvKreKPwNHtfASP3Z7LpcSZJhAr-wTK__o
48,-EPISODE_UPDATE,appId-4,vZ2luU3RhdHVzIjoiQUNUSVZFIn0.YNgpMeZPUyth_HwVsCWQTMiA6afrs33CR7I0OgIDCbI
32,-CONTENT_SUBSCRIBE,appId-5,LuU3RhdHVzIjoiQUNUSVZFIn0.r1GIzwUCKe12A4cqyHqmt8D3wLAHW_QgytrZUvy6tFE
42,-CONTENT_SUBSCRIBE,appId-6,luU3RhdHVzIjoiQUNUSVZFIn0.7XpgjXbXClmyIjpu7w0uAe1oMC-KJ3AIET5nyo7VeHg
execution:
  - concurrency: 10
    ramp-up: 1m
    hold-for: 1m
    scenario: Review-Read
  - concurrency: 10
    ramp-up: 1m
    hold-for: 1m
    scenario: Review-Update

scenarios:
  Review-Read:
    default-address: http://localhost:8080
    requests:
      - url: /v1/my-review?episodeId=${content_id}
        headers:
          Authorization: ${token}
    data-sources:
      - path: input-data.csv
        delimiter: ','
        quoted: false
        encoding: "utf-8"
        loop: true
        variable-names: content_id,direction,appId,token
        random-order: true
  Review-Update:
    default-address: http://localhost:8080
    requests:
      - url: /v1/reviews
        method: PUT
        headers:
          Authorization: ${token}
          Content-Type: application/json
        body-file: data/review.json
    data-sources:
      - path: input-data.csv
        delimiter: ','
        quoted: false
        encoding: "utf-8"
        loop: true
        variable-names: content_id,direction,appId,token
        random-order: true

Jmeter 사용하는 경우 Function을 이용하여 동적으로 데이터를 생성할 수도 있습니다.

Apache JMeter – User’s Manual: Functions and Variables

execution:
  - concurrency: 10
    ramp-up: 1m
    hold-for: 1m
    scenario: Subscription-Read
  - concurrency: 10
    ramp-up: 1m
    hold-for: 1m
    scenario: Subscription-Read-Random-Offset

scenarios:
  Subscription-Read:
    default-address: http://localhost:8080
    requests:
      - url: /v1/subscriptions?offset=${__jexl2(30 * ${__counter(TRUE)})}&limit=10&sort=${direction}
        headers:
          Authorization: ${token}
    data-sources:
      - path: input-data.csv
        delimiter: ','
        quoted: false
        encoding: "utf-8"
        loop: true
        variable-names: content_id,direction,appId,token
        random-order: true
  Subscription-Read-Random-Offset:
    default-address: http://localhost:8080
    requests:
      - url: /v1/subscriptions?offset=${__Random(00000,10000)}&limit=10&sort=${direction}
        headers:
          Authorization: ${token}
    data-sources:
      - path: input-data.csv
        delimiter: ','
        quoted: false
        encoding: "utf-8"
        loop: true
        variable-names: content_id,direction,appId,token
        random-order: true

artifacts에 생성되는 결과 디렉터리 형식 지정

taurus 기본 설정으로 테스트를 수행하면 artifacts 디렉터리에 날짜로 디렉터리가 생성되고 하위에 관련 결과들이 저장됩니다.

$ cd artifacts
$ ls
2021-05-22_14-16-34.949830                          2021-05-20_09-33-23.239777
2021-05-22_13-20-49.508754                          2021-05-20_09-32-06.374985
2021-05-21_08-56-01.344775                          2021-05-20_09-29-45.010591
2021-05-21_08-24-38.006128                          2021-05-20_09-28-25.643505
2021-05-20_15-36-37.393026                          2021-05-20_09-16-35.951538

서비스별로 인지하기 쉽도록 결과 디렉터리 형식을 지정할 수 있습니다.

execution:
// 이하 생략
scenarios:
// 이하 생략
settings:
  artifacts-dir: /tmp/artifacts/subscription-%Y-%m-%d_%H-%M-%S.%f
$ cd artifacts
$ ls
subscription-2021-05-22_14-16-34.949830   subscription-2021-05-20_09-33-23.239777
subscription-2021-05-22_13-20-49.508754   subscription-2021-05-20_09-32-06.374985
subscription-2021-05-21_08-56-01.344775   subscription-2021-05-20_09-29-45.010591
subscription-2021-05-21_08-24-38.006128   subscription-2021-05-20_09-28-25.643505
subscription-2021-05-20_15-36-37.393026   subscription-2021-05-20_09-16-35.951538

연재글 이동[이전글] Gatling을 이용한 웹 애플리케이션 부하 테스트(2) – Scala로 테스트 코드 작성하기