wrk: 명령줄 API 부하 테스트 방법

wrk를 사용하여 명령줄에서 API를 부하 테스트하는 방법 배우기: 설치, 스레드 및 연결 플래그, 지연 시간 출력 읽기, Lua를 통한 POST 요청.

Ashley Innocent

Ashley Innocent

6 July 2026

wrk: 명령줄 API 부하 테스트 방법

Apidog 엔터프라이즈

온프레미스 배포

SSO & RBAC

SOC 2 준수

Apidog Enterprise 살펴보기

엔드포인트를 배포했습니다. 브라우저에서는 잘 작동합니다. 하지만 400명이 동시에 접속했을 때 무슨 일이 일어날지는 전혀 알 수 없습니다. 지연 시간이 일정하게 유지될까요, 아니면 99번째 백분위수가 폭증할까요? 이 시스템이 초당 1,000개의 요청을 처리할 수 있을까요, 아니면 300개에서 무너질까요?

wrk가 그 질문에 답해줍니다. wrk는 URL에 많은 HTTP 트래픽을 발생시키고 해당 부하에서 서버가 얼마나 빠르게 응답했는지 보고하는 작은 명령줄 도구입니다.

버튼

wrk란 무엇이며 언제 사용해야 하는가

wrk는 최신 HTTP 벤치마킹 도구입니다. 단일 멀티코어 머신에서 부하를 생성하고 서버가 반환하는 지연 시간과 요청 속도를 측정합니다. 멀티스레딩과 확장 가능한 이벤트 루프(Linux에서는 epoll, macOS에서는 kqueue)를 사용하므로, 여러 로드 박스(load box) 없이도 하나의 인스턴스가 많은 트래픽을 처리할 수 있습니다.

순수한 성능 수치를 원할 때 wrk를 사용하세요:

wrk는 벤치마킹 도구이지 테스트 스위트가 아닙니다. 속도를 측정합니다. JSON 본문이 올바른지, 상태 코드가 200인지, API 계약이 유지되었는지 확인하지 않습니다. 이 차이점을 명심하십시오. 이 내용은 wrk를 실제 테스트 워크플로에 어떻게 적용하는지 바꾸기 때문에 끝부분에서 다시 다룰 것입니다. 더 넓은 그림을 먼저 보고 싶다면, 이 API 부하 테스트 가이드가 wrk가 실천하는 개념을 다룹니다.

wrk 설치

macOS

Homebrew는 미리 빌드된 바이너리를 제공하며, 가장 쉬운 방법입니다:

brew install wrk

Apple Silicon에서는 이 점이 중요합니다. 소스에서 빌드하면 LuaJIT ARM64 문제에 부딪힐 수 있으므로, Homebrew 바이너리를 사용하면 이러한 골치 아픈 일을 덜 수 있습니다.

Linux (소스에서 빌드)

공식 apt 패키지가 없으므로 직접 빌드해야 합니다. 먼저 툴체인과 OpenSSL 헤더를 설치하세요:

sudo apt-get install build-essential libssl-dev git -y

그런 다음 복제하고 컴파일하세요:

git clone https://github.com/wg/wrk.git
cd wrk
make

그러면 현재 디렉터리에 wrk 바이너리가 생성됩니다. 어디서든 호출할 수 있도록 PATH에 추가하세요:

sudo cp wrk /usr/local/bin

실행되는지 확인하세요:

wrk --version

기본 명령어

모든 wrk 실행의 형태는 다음과 같습니다:

wrk -t12 -c400 -d30s http://127.0.0.1:8080/index.html

네 가지가 있습니다. 각 플래그를 살펴보겠습니다.

항상 사용하게 될 두 가지 플래그:

자주 사용하게 될 실행은 다음과 같습니다:

wrk -t8 -c200 -d30s --latency http://localhost:3000/api/users

8개 스레드, 200개 연결, 30초 실행 후 전체 지연 시간 분포가 출력됩니다.

결과 읽기

wrk는 간결한 보고서를 출력합니다. 여기 작은 서비스에 대한 실제 실행 예시가 있습니다:

Running 5s test @ http://10.135.232.163:3000
  2 threads and 5 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.82ms    2.64ms  26.68ms   85.81%
    Req/Sec   550.90    202.40     0.98k    68.00%
  5494 requests in 5.01s, 1.05MB read
Requests/sec:   1096.54
Transfer/sec:    215.24KB

마지막 두 줄이 핵심 내용이므로 아래에서 위로 읽으세요.

Requests/sec는 처리량입니다: 서버가 초당 평균적으로 완료한 요청 수입니다. 여기서는 1,096입니다. 이 수치는 여러 실행과 코드 변경 사항을 비교할 때 사용합니다.

Transfer/sec는 대역폭입니다: 초당 전송된 데이터 양입니다. 페이로드가 크거나 CPU 바운드보다는 대역폭 바운드라고 의심될 때 유용합니다.

이제 평균뿐만 아니라 분포를 설명하는 스레드 통계 테이블입니다:

+/- Stdev 열은 표본 중 몇 퍼센트가 한 표준 편차 내에 속하는지를 알려줍니다. 비율이 낮을수록 더 넓고 예측하기 어려운 분포를 의미합니다.

5494 requests in 5.01s 라인은 실제로 실행이 밀어낸 총량을 확인시켜줍니다.

--latency를 추가하면 wrk는 백분위수 블록을 출력하여 꼬리 부분을 직접 확인할 수 있습니다:

  Latency Distribution
     50%    3.21ms
     75%    4.86ms
     90%    7.09ms
     99%   14.13ms

주목해야 할 숫자는 99번째 백분위수입니다. 99%의 요청이 14ms 내에 완료되지만 평균이 3.82ms라면, 100명 중 1명의 사용자는 평균이 암시하는 것보다 훨씬 더 오래 기다리고 있는 것입니다. 평균은 꼬리에 대해 거짓말을 합니다. 백분위수는 그렇지 않습니다.

Lua 스크립트로 POST 요청 및 사용자 정의 헤더 전송

기본적으로 wrk는 GET 요청을 보냅니다. POST 요청을 보내거나, 본문을 추가하거나, 사용자 정의 헤더를 설정하려면 -s 옵션과 함께 Lua 스크립트를 전달합니다.

post.lua라는 파일을 생성하세요:

wrk.method = "POST"
wrk.body   = '{"name": "Ada", "role": "engineer"}'
wrk.headers["Content-Type"] = "application/json"

세 가지 필드가 작동합니다. wrk.method는 HTTP 동사를 설정합니다. wrk.body는 요청 본문을 설정합니다. wrk.headers는 각 키가 헤더 이름인 테이블입니다.

-s를 스크립트에 지정하여 실행합니다:

wrk -t4 -c100 -d30s -s post.lua --latency http://localhost:3000/api/users

JSON 대신 폼 인코딩된 POST의 경우, wrk 저장소에는 다음과 같은 예시가 포함되어 있습니다:

wrk.method = "POST"
wrk.body   = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"

더 간단한 경우에는 스크립트 없이 -H 플래그로 헤더를 설정할 수도 있습니다:

wrk -t4 -c100 -d30s -H "Authorization: Bearer TOKEN123" --latency http://localhost:3000/api/protected

하나 또는 두 개의 헤더에는 -H를 사용하세요. 본문, GET이 아닌 메서드 또는 요청별 로직이 필요한 경우 Lua 스크립트를 사용하세요.

한계: wrk는 정확성을 확인하지 않습니다

사람들이 놓치는 부분이 바로 이겁니다. wrk는 서버가 얼마나 빠르게 응답했는지를 알려줍니다. 응답이 올바른지는 알려주지 않습니다.

모든 요청에 대해 HTTP 500을 반환하는 엔드포인트에 wrk를 사용하면, 높은 초당 요청 수와 함께 깔끔해 보이는 보고서를 얻게 될 것입니다. wrk는 완료된 HTTP 교환을 계산합니다. 상태 코드를 단언하거나, 스키마에 대해 응답 본문을 검증하거나, API가 수행해야 할 작업을 제대로 수행했는지 확인하지 않습니다. 오류는 서버가 요청을 일찍 거부할수록 요청당 더 적은 작업을 하기 때문에 빠르게 보일 수도 있습니다.

따라서 wrk는 "부하 상황에서 충분히 빠른가?"라는 질문에 답합니다. "올바른가?"라는 질문에는 답할 수 없습니다. 두 질문 모두 중요하며, 서로 다른 도구가 필요합니다. 손상된 엔드포인트에 대한 부하 수치는 신뢰할 수 없는 수치입니다. 이것이 바로 팀들이 벤치마킹 도구와 기능 테스트 스위트를 함께 사용하는 이유입니다. 하나는 속도를 증명하고, 다른 하나는 동작을 증명합니다.

Apidog와 기능 테스트의 적합성

깔끔한 워크플로는 두 가지 계층으로, 순서대로 실행됩니다.

첫째, 동작을 검증하세요. 엔드포인트가 얼마나 빠른지에 신경 쓰기 전에, 그것이 올바른지 확인하십시오. Apidog에서는 실제 요청을 보내고 반환되는 내용(상태 코드, JSON 필드, 응답 스키마 및 비즈니스 로직)을 단언하는 테스트 시나리오를 구축합니다. 요청을 연결하고, 단계 간에 데이터를 전달하며, 여러 환경에서 동일한 시나리오를 실행할 수 있습니다. 이것은 wrk가 기쁘게 벤치마킹하는 손상된 500 오류를 잡아내는 계층입니다.

그 다음, 처리량을 벤치마킹하세요. 동작이 검증되면, 동일한 엔드포인트에 대해 wrk를 실행하여 동시성 및 지속적인 부하 상황에서 어떻게 견디는지 확인하십시오. Apidog에는 기능 및 부하 작업을 한 곳에서 유지하고 싶다면 내장 성능 테스트도 있지만, wrk는 순수한 명령줄 벤치마킹을 위한 훌륭한 전용 도구입니다.

기능 계층은 노트북뿐만 아니라 CI에서도 실행됩니다. Apidog CLI는 헤드리스(headless)이므로 Node를 실행할 수 있는 모든 파이프라인 단계에 통합할 수 있습니다. 설치 방법:

npm install -g apidog-cli

그런 다음 저장된 테스트 시나리오 또는 스위트를 ID로 실행합니다:

apidog run \
  --access-token "$APIDOG_ACCESS_TOKEN" \
  -t <scenarioOrSuiteId> \
  -e <environmentId> \
  -r cli,html,junit

-t는 실행할 시나리오, 폴더 또는 스위트 ID입니다. -e는 환경 ID입니다. -rcli, html, json, junit 중 하나 이상의 보고서 형식을 선택합니다. JUnit 출력은 대부분의 CI 시스템에 직접 연결되어 통과/실패 게이팅에 사용됩니다. 데이터 기반 실행의 경우, -d (또는 --iteration-data)와 함께 파일 경로 또는 테스트 데이터 ID를 추가하여 여러 입력 행에 대해 동일한 시나리오를 반복할 수 있습니다.

CLI는 저장된 Apidog 시나리오와 스위트를 실행합니다. 이는 헤드리스이며, 대화형 요청 발신자가 아니고, 부하 생성기도 아닙니다. 이는 정확성 게이트입니다. wrk는 속도 측정기입니다. 파이프라인에서 정확성 게이트를 실행한 다음 (복사하여 붙여넣기 구성은 이 CLI CI/CD 가이드 또는 GitHub Actions 가이드를 참조), 처리량 수치가 필요할 때 wrk로 벤치마킹하십시오. 전체 CLI 참조는 나머지 플래그를 다룹니다.

FAQ

wrk와 ab(ApacheBench)의 차이점은 무엇인가요? 둘 다 HTTP 부하를 발생시키고 초당 요청 수를 보고합니다. wrk는 멀티스레드이며 이벤트 루프를 사용하여 단일 머신에서 더 많은 부하를 생성하고 높은 동시성을 더 잘 처리합니다. ab는 단일 스레드입니다. 단일 상자에서 발생하는 과중한 부하에 대해서는 wrk가 일반적으로 더 확장성이 좋습니다. 둘 다 응답의 정확성을 확인하지는 않습니다.

몇 개의 스레드와 연결을 사용해야 하나요? CPU 코어당 하나의 스레드로 시작하고, 시뮬레이션하려는 동시성 수준에 맞게 연결 수를 설정하세요. 8개 코어가 있고 200개의 동시 클라이언트를 모델링하려면 -t8 -c200을 시도해 보세요. 클라이언트 머신을 주시하세요. wrk 자체가 CPU 바운드라면, 그 수치는 서버의 한계가 아닌 부하 생성기의 한계를 반영합니다. 처리량이 더 이상 증가하지 않을 때까지 연결을 늘리세요.

wrk로 HTTPS 엔드포인트를 테스트할 수 있나요? 예. https:// URL을 지정하면 wrk가 TLS를 처리합니다. 이것이 Linux 빌드에 libssl-dev가 필요한 이유입니다. TLS 핸드셰이크는 양쪽 끝에서 CPU 비용을 추가하므로, 일반 HTTP보다 HTTPS에 대한 순수 처리량이 더 낮을 것으로 예상됩니다.

wrk는 응답 본문이나 상태 코드를 검증하나요? 아니요. wrk는 완료된 HTTP 교환을 세고 타이밍을 측정합니다. 상태 코드나 본문에 대해 단언하지 않으므로, 오류를 반환하는 엔드포인트도 높은 초당 요청 수를 기록할 수 있습니다. Apidog CLI를 통해 실행되는 기능 테스트 스위트와 같은 것을 사용하여 정확성을 확인한 다음, wrk를 사용하여 처리량을 측정하세요.

부하 테스트는 얼마나 오래 실행해야 하나요? 콜드 캐시 및 JIT 컴파일과 같은 워밍업 효과를 극복할 수 있을 만큼 충분히 길어야 합니다. 빠른 확인을 위해서는 몇 초도 괜찮지만, 30초에서 몇 분 정도는 더 안정적인 수치를 제공하고 지속적인 부하 상황에서만 나타나는 성능 저하를 드러냅니다. 합리적인 기본값으로 -d30s를 사용하고, 느린 누수를 추적할 때는 더 길게 설정하세요.

Apidog에서 API 설계-첫 번째 연습

API를 더 쉽게 구축하고 사용하는 방법을 발견하세요