Skip to main content

Artillery 시나리오 설계

7. 동적 데이터와 인증 처리

JWT 토큰 추출

로그인 응답이 다음과 같다고 가정한다.

{
"accessToken": "eyJ..."
}

Artillery에서는 capture로 토큰을 변수에 저장하고 이후 요청에서 사용할 수 있다.

- post:
url: "/api/auth/login"
json:
email: "{{ email }}"
password: "{{ password }}"
capture:
- json: "$.accessToken"
as: "token"

- get:
url: "/api/me"
headers:
authorization: "Bearer {{ token }}"

환경 변수 사용

config:
target: "{{ $processEnvironment.TARGET_URL }}"
TARGET_URL=https://staging.example.com npx artillery run tests/performance/api.yml

processor.js 예시

Artillery는 config.processor로 JS 파일을 로드해 hook이나 사용자 함수를 실행할 수 있다.

const crypto = require("crypto");

function setRandomUser(context, events, done) {
const id = crypto.randomUUID();

context.vars.email = `loadtest+${id}@example.com`;
context.vars.password = process.env.LOAD_TEST_PASSWORD || "password1234";
context.vars.itemTitle = `item-${id}`;

return done();
}

function addRequestId(requestParams, context, events, done) {
requestParams.headers = requestParams.headers || {};
requestParams.headers["x-request-id"] = crypto.randomUUID();
return done();
}

module.exports = {
setRandomUser,
addRequestId,
};

YAML에서 사용:

config:
processor: "./processor.js"

scenarios:
- beforeScenario: "setRandomUser"
flow:
- get:
url: "/api/items"
beforeRequest: "addRequestId"

CSV payload 사용

계정이 미리 준비되어 있다면 CSV를 사용한다.

email,password
user1@example.com,password
user2@example.com,password
config:
payload:
path: "./payloads/users.csv"
fields:
- "email"
- "password"

8. 테스트 강도 설계

arrivalRate와 동시 사용자 수

arrivalRate는 초당 새로 시작되는 가상 사용자 수다. 동시 사용자 수 자체가 아니다.

동시 사용자 수는 대략 다음 요인으로 결정된다.

동시 실행 VU ~= arrivalRate * 시나리오 평균 수행 시간

예를 들어 arrivalRate: 50이고 한 시나리오가 평균 4초 걸리면 동시에 약 200명의 VU가 실행될 수 있다.

maxVusers

서버가 느려져 시나리오가 오래 걸리면 동시 VU가 계속 증가할 수 있다. 이때 maxVusers로 상한을 둘 수 있다.

config:
phases:
- duration: 300
arrivalRate: 50
maxVusers: 300

단계별 설계 예시

phases:
- name: "warmup"
duration: 120
arrivalRate: 5
rampTo: 20
- name: "target-load"
duration: 600
arrivalRate: 50
- name: "stress-ramp"
duration: 600
arrivalRate: 50
rampTo: 200
- name: "recovery"
duration: 300
arrivalRate: 20

권장 순서:

  1. 로컬에서 작은 부하로 스크립트 검증
  2. staging에서 목표 부하의 10~20%로 검증
  3. 목표 부하 load test
  4. 목표 부하 초과 stress test
  5. 1~4시간 이상 soak test

9. 성능 지표 해석

Artillery 결과에서 주로 볼 지표:

지표의미해석 기준
RPS초당 처리 요청 수목표 트래픽을 안정적으로 처리하는지 확인
latency median일반적인 응답 시간평균 사용자 경험에 가까움
latency p95느린 5% 요청의 경계SLO 기준으로 많이 사용
latency p99매우 느린 요청의 경계tail latency와 장애 징후 확인
error rate실패 요청 비율4xx/5xx, timeout, connection error 포함 여부 확인
HTTP status codes상태 코드 분포429, 500, 502, 503 증가 여부 확인
timeout응답 제한 시간 초과서버 포화, 네트워크, LB 제한 가능성

해석할 때는 Artillery 결과만 보지 말고 서버 지표와 함께 본다.

  • latency p95 상승 + CPU 90% 이상: CPU 병목 가능성
  • latency 상승 + DB/외부 API 지표 악화: 앱 외부 의존성 가능성
  • RPS 정체 + 5xx 증가: 서버 포화 또는 connection pool 고갈 가능성
  • 429 증가: rate limit 또는 upstream 보호 정책 작동
  • 메모리 지속 증가: leak 또는 GC pressure 가능성

10. WebSocket 테스트

Artillery의 WebSocket 엔진은 engine: ws를 사용한다.

config:
target: "ws://localhost:3000"
phases:
- duration: 120
arrivalRate: 20

scenarios:
- name: "websocket echo"
engine: ws
flow:
- connect: "{{ target }}/ws"
- send: '{"type":"ping"}'
- think: 1
- send: '{"type":"message","body":"hello"}'

인증 토큰을 쿼리 스트링으로 전달하는 경우:

config:
target: "ws://localhost:3000"
variables:
token: "test-token"

scenarios:
- engine: ws
flow:
- connect: "{{ target }}/ws?token={{ token }}"
- send: '{"type":"ping"}'

11. Socket.IO 테스트

Socket.IO는 engine: socketio를 사용한다.

config:
target: "http://localhost:3000"
phases:
- duration: 120
arrivalRate: 20
socketio:
transports:
- "websocket"

scenarios:
- name: "socket.io chat"
engine: socketio
flow:
- emit:
- "join"
- roomId: "load-test"
- think: 1
- emit:
- "message"
- roomId: "load-test"
text: "hello from artillery"

주의:

  • Socket.IO 서버 버전과 Artillery 엔진 호환성을 확인한다.
  • 브라우저와 달리 쿠키, 헤더, transport 설정이 자동으로 같지 않다.
  • 인증이 handshake query/header에 묶여 있으면 실제 서버 인증 방식과 동일하게 구성해야 한다.