엔드포인트를 배포했습니다. Postman에서는 올바른 JSON을 반환합니다. 하지만 200개의 클라이언트가 동시에 요청을 보낼 때 어떤 일이 벌어질지는 전혀 알 수 없습니다. 초당 500개의 요청을 처리할 수 있을까요, 아니면 50개만 되어도 지연 시간이 엉망이 될까요? ApacheBench는 이 질문에 단 하나의 명령으로 답해줍니다.
ab로 호출되는 ApacheBench는 단일 URL에 대해 고정된 수의 HTTP 요청을 발생시키고 처리량과 지연 시간을 보고하는 명령줄 도구입니다. Apache HTTP 서버에 포함되어 있으며 수십 년 동안 사용되어 왔습니다. 작고 빠르게 실행되며, 하나의 엔드포인트가 얼마나 많은 부하를 감당할 수 있는지 빠르게 파악할 수 있게 해줍니다.
이 가이드는 ab 설치, 기본 테스트 실행, POST 엔드포인트 테스트, 출력 판독, 그리고 ab가 적절한 도구가 아닌 경우를 다룹니다. 여기의 모든 명령은 공식 Apache ab 참조에 문서화된 플래그에 해당합니다.
ApacheBench는 무엇이며 어디에서 왔는가
ab는 Apache HTTP 서버와 함께 번들로 제공되는 벤치마킹 클라이언트입니다. 이 이름은 ApacheBench의 줄임말입니다. 단일 URL에 연결을 열고, 동시성 설정이 허용하는 한 빠르게 요청을 보내며, 각 응답 시간을 측정하고 요약을 출력합니다.

이 도구는 한 가지를 잘 측정합니다: 단일 엔드포인트가 초당 얼마나 많은 요청을 처리할 수 있는지, 그리고 부하 상태에서 응답 시간이 어떻게 분포되는지. 이는 단일 URL에 대한 처리량과 지연 시간을 나타냅니다.
무엇을 하지 않는지도 중요합니다. ab는 응답 본문이 올바른지 확인하지 않습니다. 스키마를 검증하거나 필드를 단언하지 않습니다. 로그인, 데이터 가져오기, 업데이트와 같은 다단계 흐름을 수행하지 않습니다. 단일 URL을 요청하고 횟수를 셉니다. 이러한 범위를 염두에 둔다면 ab는 유용하게 사용될 것입니다. 더 많은 것을 기대하면 실망할 것입니다.
ab가 속한 분야에 대한 더 넓은 시야를 원한다면 API 부하 테스트란 무엇인지와 API 응답 시간이 왜 중요한지를 참조하세요.
ab 설치
ab는 Apache 유틸리티와 함께 패키징되어 제공됩니다. 패키지 이름은 플랫폼에 따라 다릅니다.
Debian 및 Ubuntu에서는 apache2-utils 패키지를 설치합니다:
sudo apt-get update
sudo apt-get install -y apache2-utils
CentOS, RHEL 및 Fedora에서는 httpd-tools 패키지입니다:
# CentOS 7
sudo yum install -y httpd-tools
# Fedora and CentOS 8+
sudo dnf install -y httpd-tools
macOS에서는 시스템에 Apache가 포함되어 있으므로 ab가 이미 존재합니다. 확인해보세요:
ab -V
Version 2.3과 같은 버전 줄이 표시되어야 합니다. macOS에서 명령이 없으면 Homebrew의 Apache formula를 통해 설치하세요. ab -V가 버전을 출력하면 준비가 된 것입니다.
기본 부하 테스트 실행
항상 사용할 두 가지 플래그는 -n과 -c입니다.
-n requests는 총 수행할 요청 수를 설정합니다. 기본값은 단일 요청이므로 아무것도 알려주지 않으니 항상 이 값을 설정하세요.-c concurrency는 한 번에 실행할 요청 수를 설정합니다. 기본값은 1이며, 이는 완전히 직렬로 실행된다는 의미입니다.
다음은 JSON 엔드포인트에 대해 1000개의 요청을 50개씩 동시에 보내는 예입니다:
ab -n 1000 -c 50 https://api.example.com/v1/users
후행 경로에 유의하세요. ab는 경로가 포함된 전체 URL이 필요합니다. 경로 없이 bare 호스트를 지정하면 오류가 발생합니다. 루트의 경우 후행 슬래시를 사용하세요: https://api.example.com/.
실제 클라이언트는 요청당 새 연결을 여는 대신 TCP 연결을 재사용합니다. -k를 추가하여 HTTP KeepAlive를 활성화하면 ab가 세션 내에서 연결을 재사용합니다:
ab -n 1000 -c 50 -k https://api.example.com/v1/users
-k 실행은 일반적으로 브라우저나 잘 동작하는 API 클라이언트가 작동하는 방식에 더 가깝습니다. 왜냐하면 모든 요청에서 연결 설정 비용을 지불하지 않기 때문입니다. 두 숫자를 비교하여 지연 시간 중 얼마나 많은 부분이 연결 오버헤드인지 확인할 수 있습니다.
요청 횟수 대신 시간으로 실행을 제한할 수도 있습니다. -t는 최대 초 수를 설정하며 내부적으로 -n 50000을 암시하므로, 두 제한 중 먼저 도달하는 시점에 테스트가 중지됩니다:
ab -t 30 -c 50 -k https://api.example.com/v1/users
이는 동시성 50으로 최대 30초 동안 실행됩니다. 고정된 횟수 대신 고정된 시간 동안 측정값을 원할 때 유용합니다.
POST 엔드포인트 테스트
대부분의 API 작업은 GET이 아닙니다. POST를 테스트하려면 요청 본문을 파일에 넣고 -p로 전달하세요. 또한 -T로 콘텐츠 유형을 설정해야 합니다. 그렇지 않으면 서버가 본문을 거부할 것입니다.
페이로드를 생성합니다:
cat > payload.json <<'EOF'
{"name": "Ada Lovelace", "email": "ada@example.com"}
EOF
그런 다음 보냅니다:
ab -n 500 -c 25 -k \
-p payload.json \
-T application/json \
https://api.example.com/v1/users
-p 플래그는 POST 본문이 포함된 파일 이름을 지정합니다. -T 플래그는 Content-Type 헤더를 설정합니다. 기본 콘텐츠 유형은 text/plain이며, 이는 JSON API가 거의 원하지 않는 것이므로 -T application/json을 명시적으로 설정해야 합니다.
엔드포인트에 인증 또는 다른 헤더가 필요한 경우, -H를 사용하여 추가하세요. 각 헤더에 대해 플래그를 반복합니다:
ab -n 500 -c 25 -k \
-p payload.json \
-T application/json \
-H "Authorization: Bearer YOUR_TOKEN" \
https://api.example.com/v1/users
JSON 요청 본문을 수동으로 작성하는 방법에 대한 복습은 curl을 사용하여 JSON 데이터를 POST하는 방법을 참조하세요. 동일한 본문이 ab 페이로드 파일로 작동합니다.
출력 판독
실행 결과는 숫자 블록을 출력합니다. 다음은 간략한 예입니다:
Concurrency Level: 50
Time taken for tests: 4.212 seconds
Complete requests: 1000
Failed requests: 0
Non-2xx responses: 0
Requests per second: 237.42 [#/sec] (mean)
Time per request: 210.598 [ms] (mean)
Time per request: 4.212 [ms] (mean, across all concurrent requests)
Transfer rate: 142.31 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 5 18 9.4 16 64
Processing: 22 189 41.2 182 310
Waiting: 21 177 39.8 171 295
Total: 31 207 42.7 201 338
Percentage of the requests served within a certain time (ms)
50% 201
66% 221
75% 236
90% 268
95% 291
99% 324
100% 338 (longest request)
다음 필드들을 먼저 읽으세요:
- Requests per second는 처리량의 주요 지표입니다. 요청 수를 총 시간으로 나눈 값입니다. 높을수록 좋습니다.
- Failed requests와 Non-2xx responses는 서버가 실제로 부하를 처리했는지, 아니면 오류를 내기 시작했는지 알려줍니다. 절반의 응답이 500 오류라면 높은 Requests per second 값은 아무 의미가 없습니다. 처리량 수치를 신뢰하기 전에 항상 이 두 가지를 확인하세요.
- Time per request는 두 번 나타납니다. 첫 번째 줄은 단일 사용자가 대기하는 평균 시간입니다(동시성 * 총 시간 / 요청). "across all concurrent requests"라고 표시된 두 번째 줄은 완료된 요청 사이의 평균 간격입니다. 첫 번째 숫자가 사용자들이 체감하는 시간입니다.
Percentage of the requests served within a certain time 표는 가장 유용한 부분입니다. 이는 백분위수 분석입니다. 50% 줄은 중앙값입니다. 95%와 99% 줄은 느린 응답 시간의 꼬리 부분을 보여줍니다. 예시에서 절반의 요청이 201ms 이내에 완료되었지만, 1%는 324ms 이상이 걸렸습니다. 꼬리 지연 시간은 실제 사용자들이 불편함을 느끼는 부분으로, 평균보다 95번째 및 99번째 백분위수를 더 주의 깊게 살펴보세요.
차트를 위한 원시 요청별 수치를 원하나요? -e results.csv를 추가하여 백분위수-시간 쌍의 CSV를 작성하거나, -g results.tsv를 추가하여 gnuplot 친화적인 파일을 작성하세요.
ab가 적절한 도구가 아닌 경우
ab는 의도적으로 범위가 좁습니다. 오용하지 않도록 한계를 명확하게 언급하는 것이 중요합니다.
실행당 하나의 URL. ab는 단일 엔드포인트를 공격합니다. 인증, 리소스 생성, 그리고 다시 읽어들이는 것과 같은 시퀀스를 스크립트로 작성할 수 없습니다. 실제 사용자 여정은 순서대로 여러 엔드포인트를 건드리는데, ab는 이러한 개념이 없습니다.
정확성 검사 없음. ab는 상태 코드와 바이트 길이를 계산합니다. JSON을 파싱하거나 필드가 예상 값과 동일한지 확인하지 않습니다. 응답이 구조적으로 잘못되어도 성공으로 간주될 수 있습니다. 부하 수치는 통과하는 테스트 스위트를 대체할 수 없습니다.
오래된 HTTP 처리. 공식 문서에 따르면 ab는 HTTP/1.x를 완전히 구현하지 않으며 일부 예상되는 형식의 응답만 허용합니다. HTTP/2 지원은 없습니다. HTTP/2에서 다르게 동작하는 서버의 경우, ab는 이를 반영하지 못할 것입니다.
단일 머신 부하. ab는 하나의 박스와 하나의 프로세스에서 실행됩니다. 특정 동시성을 넘어서면, 서버의 한계 대신 자신의 클라이언트의 한계를 측정하게 됩니다. 문서에서는 ab 자체의 파싱이 프로파일에서 병목 현상으로 나타날 수 있다고 경고하기도 합니다.
이러한 점들이 ab를 나쁜 도구로 만드는 것은 아닙니다. 이는 특정 목적을 위한 도구라는 의미입니다: 단일 엔드포인트에 대한 빠른 처리량 조사 도구. 스크립트 기반 흐름, 분산 부하, 또는 HTTP/2가 필요할 때는 그러한 목적에 맞게 구축된 도구를 사용하세요. JMeter는 다단계 시나리오와 분산 실행을 처리하며, 옵션을 비교 중이라면 더 넓은 범위의 부하 테스트 도구 모음이 있습니다.
기능 테스트가 적합한 곳
처리량은 한 가지 축입니다. 정확성은 다른 축이며, ab는 이를 다루지 않습니다. 엔드포인트를 부하 테스트하기 전에, 정상적인 조건에서 올바른 형식으로 올바른 데이터를 반환하는지 알아야 합니다. 이는 기능 및 계약 테스트이며, 다른 작업입니다.
이것이 완전한 API 플랫폼이 ab와 나란히 제 역할을 하는 지점입니다. Apidog는 시각적 단언으로 테스트 시나리오를 구축하고, 요청을 다단계 흐름으로 연결하고, 스키마에 대해 응답을 검증할 수 있도록 해줍니다. 이는 ab가 설계상 할 수 없는 일입니다. 이러한 시나리오를 한 번 저장하면 어디서든 실행할 수 있습니다.
지속적 통합을 위해 Apidog CLI는 저장된 시나리오를 헤드리스 방식으로 실행합니다. Node로 설치하세요:
npm install -g apidog-cli
그런 다음 선택한 환경에 대해 저장된 시나리오 또는 스위트를 실행하고, CI에서 아카이브할 수 있는 보고서를 출력합니다:
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t <scenarioOrSuiteId> \
-e <environmentId> \
-r cli,html,junit
-t 플래그는 ID로 저장된 시나리오, 폴더 또는 스위트를 대상으로 합니다. -e 플래그는 환경을 선택합니다. -r 플래그는 cli, html, json 및 junit 중에서 하나 이상의 리포터를 선택합니다. 데이터 기반 실행의 경우, 데이터 파일 경로 또는 테스트 데이터 ID와 함께 -d (또는 --iteration-data)를 추가합니다. CLI는 헤드리스이며 저장된 시나리오를 실행하므로, Node를 실행할 수 있는 모든 CI 단계에 적합합니다. 이는 요청 발송자도, 부하 생성기도 아니며, ab가 실행하도록 의도되지 않은 기능 테스트를 실행합니다.
건전한 설정은 두 가지 모두를 사용합니다. Apidog 시나리오를 실행하여 엔드포인트가 올바른지 증명합니다. ab를 실행하여 충분히 빠른지 증명합니다. 정확성 측면에서는 Apidog 성능 테스트 가이드와 일반적인 API 성능 테스트 튜토리얼을 참조하세요.
자주 묻는 질문
ApacheBench는 Apache 서버 전용인가요?
아닙니다. 이름에도 불구하고 ab는 모든 서버에 일반 HTTP 및 HTTPS 요청을 보냅니다. Nginx, Node, Go, Python 또는 HTTP를 사용하는 모든 호스트에 대해 작동합니다. Apache와의 연결은 도구가 Apache HTTP 서버와 함께 제공된다는 점뿐입니다.
어떤 동시성 및 요청 수를 사용해야 하나요?
낮게 시작하여 점진적으로 올리세요. -n 1000 -c 10으로 시작한 다음 -c를 25, 50, 100으로 올려서 초당 요청 수가 더 이상 증가하지 않고 실패한 요청이 나타나기 시작하는 지점을 확인하세요. 이 변곡점이 대략 엔드포인트가 포화되는 지점입니다. 큰 반올림 숫자 대신 예상되는 실제 트래픽에 맞춰 최고 동시성을 조정하세요.
API가 잘 작동하는데 실패한 요청이 많은 이유는 무엇인가요?
ab는 응답 길이가 요청마다 다를 경우 요청을 실패로 표시하는데, 이는 동적 JSON의 경우 정상입니다. -l 플래그를 추가하여 길이 차이를 실패로 계산하지 않도록 하세요. 그런 다음 Non-2xx responses 줄을 확인하여 실제 오류가 있는지 확인하세요.
ab가 로그인 토큰이 필요한 엔드포인트를 테스트할 수 있나요?
네, 이미 토큰이 있다면 가능합니다. -H "Authorization: Bearer YOUR_TOKEN"을 사용하여 전달하세요. ab가 할 수 없는 것은 먼저 로그인하여 새 토큰을 얻은 다음 사용하는 것입니다. 이는 다단계 흐름이며, 이를 위해서는 Apidog와 같은 시나리오 기반 도구가 필요합니다.
ab가 HTTP/2를 지원하나요?
아닙니다. ab는 HTTP/1.x를 사용하며, 공식 문서에 따르면 완전히 구현하지도 않습니다. HTTP/2 하에서의 서버 동작이 중요하다면, HTTP/2를 지원하는 부하 테스트 도구를 대신 사용하세요.
