0환경 설정
1
Java 설치 — JMeter는 Java 11+ 필요.
java -version으로 확인2
JMeter 다운로드 — 공식 사이트에서 Binary tgz 다운로드 후 압축 해제
3
GUI 실행 —
bin/jmeter.sh (Mac/Linux) 또는 bin\jmeter.bat (Windows)4
플러그인 설치 — Plugins Manager(
bin/JMeterPlugins-Manager.jar)로 3 Basic Graphs, Custom Thread Groups 추가 권장1Thread Group 기본 JMX — HTTP 부하 테스트
JMeter 테스트의 기본 단위인 JMX 파일입니다. Thread Group, HTTP Request, Summary Report를 포함한 최소 구성으로 시작합니다.
basic_load_test.jmx — 기본 HTTP 부하 테스트
100 스레드, Ramp-up 30초, 5분 반복 실행. GUI에서 열거나 CLI로 직접 실행 가능한 최소 JMX 구조.
xml<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2">
<hashTree>
<TestPlan guiclass="TestPlanGui" testname="Basic Load Test">
<elementProp name="TestPlan.user_defined_variables"
elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="BASE_URL" elementType="Argument">
<stringProp name="Argument.name">BASE_URL</stringProp>
<stringProp name="Argument.value">httpbin.org</stringProp>
</elementProp>
</collectionProp>
</elementProp>
</TestPlan>
<hashTree>
<!-- Thread Group: 100 users, 30s ramp-up, 300s duration -->
<ThreadGroup guiclass="ThreadGroupGui" testname="Users">
<intProp name="ThreadGroup.num_threads">100</intProp>
<intProp name="ThreadGroup.ramp_time">30</intProp>
<boolProp name="ThreadGroup.scheduler">true</boolProp>
<stringProp name="ThreadGroup.duration">300</stringProp>
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
</ThreadGroup>
<hashTree>
<!-- HTTP Request: GET /get -->
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testname="GET /get">
<stringProp name="HTTPSampler.domain">${BASE_URL}</stringProp>
<stringProp name="HTTPSampler.protocol">https</stringProp>
<stringProp name="HTTPSampler.path">/get</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
</HTTPSamplerProxy>
<hashTree/>
<!-- Response Assertion: status 200 -->
<ResponseAssertion guiclass="AssertionGui" testname="Status 200">
<collectionProp name="Asserion.test_strings">
<stringProp>200</stringProp>
</collectionProp>
<intProp name="Assertion.test_type">8</intProp>
<stringProp name="Assertion.test_field">Assertion.response_code</stringProp>
</ResponseAssertion>
<hashTree/>
</hashTree>
<!-- Summary Report Listener -->
<ResultCollector guiclass="SummaryReport" testname="Summary Report">
<stringProp name="filename">results/summary.csv</stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</jmeterTestPlan>
2CSV 데이터셋 로그인 — 다중 사용자 인증
실제 사용자 계정 목록을 CSV로 관리하고 각 스레드가 다른 계정으로 로그인하는 패턴입니다. 세션 쿠키를 자동으로 유지합니다.
users.csv — 테스트 계정 목록
username과 password 컬럼을 가진 사용자 데이터 파일. JMeter CSV Data Set Config로 읽어 스레드별로 순환 할당.
csvusername,password
user_01,pass_01
user_02,pass_02
user_03,pass_03
user_04,pass_04
user_05,pass_05
login_flow.jmx — CSV 로그인 + 세션 유지
CSV에서 계정을 읽어 로그인하고, HTTP Cookie Manager로 세션을 유지한 채 이후 API를 호출하는 전체 시나리오.
xml<hashTree>
<ThreadGroup testname="Login Flow">
<intProp name="ThreadGroup.num_threads">50</intProp>
<intProp name="ThreadGroup.ramp_time">30</intProp>
<boolProp name="ThreadGroup.scheduler">true</boolProp>
<stringProp name="ThreadGroup.duration">180</stringProp>
</ThreadGroup>
<hashTree>
<!-- CSV Data Set Config -->
<CSVDataSet guiclass="TestBeanGUI" testname="User Accounts">
<stringProp name="filename">users.csv</stringProp>
<stringProp name="variableNames">username,password</stringProp>
<boolProp name="recycle">true</boolProp>
<boolProp name="stopThread">false</boolProp>
<stringProp name="shareMode">shareMode.all</stringProp>
</CSVDataSet>
<hashTree/>
<!-- Cookie Manager (세션 자동 유지) -->
<CookieManager guiclass="CookiePanel" testname="Cookie Manager">
<boolProp name="CookieManager.clearEachIteration">true</boolProp>
</CookieManager>
<hashTree/>
<!-- Step 1: 로그인 POST -->
<HTTPSamplerProxy testname="POST /login">
<stringProp name="HTTPSampler.domain">your-app.example.com</stringProp>
<stringProp name="HTTPSampler.protocol">https</stringProp>
<stringProp name="HTTPSampler.path">/api/login</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
<boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
<elementProp name="HTTPsampler.Arguments">
<collectionProp name="Arguments.arguments">
<elementProp elementType="HTTPArgument">
<!-- ${username}, ${password}: CSV에서 읽은 값 자동 치환 -->
<stringProp name="Argument.value">
{"username":"${username}","password":"${password}"}
</stringProp>
</elementProp>
</collectionProp>
</elementProp>
</HTTPSamplerProxy>
<hashTree>
<!-- JSON Extractor: 응답에서 access_token 추출 -->
<JSONPostProcessor testname="Extract Token">
<stringProp name="JSONPostProcessor.referenceNames">access_token</stringProp>
<stringProp name="JSONPostProcessor.jsonPathExprs">$.access_token</stringProp>
</JSONPostProcessor>
<hashTree/>
</hashTree>
<!-- Step 2: 인증된 API 호출 -->
<HTTPSamplerProxy testname="GET /api/profile">
<stringProp name="HTTPSampler.path">/api/profile</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
</HTTPSamplerProxy>
<hashTree>
<HeaderManager testname="Auth Header">
<collectionProp name="HeaderManager.headers">
<elementProp elementType="Header">
<stringProp name="Header.name">Authorization</stringProp>
<stringProp name="Header.value">Bearer ${access_token}</stringProp>
</elementProp>
</collectionProp>
</HeaderManager>
<hashTree/>
</hashTree>
</hashTree>
</hashTree>
3Assertion 검증 — 응답 코드·본문·시간
단순 상태 코드 확인을 넘어 응답 본문, JSON 필드, 응답 시간까지 다층적으로 검증하는 패턴입니다.
assertions.jmx — Response / Duration / JSON Assertion
상태 코드 200, 응답 본문에 특정 문자열 포함 여부, 응답 시간 500ms 미만, JSON 필드값을 한 번에 검증.
xml<hashTree>
<HTTPSamplerProxy testname="GET /api/products">
<stringProp name="HTTPSampler.path">/api/products</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
</HTTPSamplerProxy>
<hashTree>
<!-- 1. 응답 코드 검증 -->
<ResponseAssertion testname="Status 200">
<collectionProp name="Asserion.test_strings">
<stringProp>200</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_code</stringProp>
<intProp name="Assertion.test_type">8</intProp> <!-- equals -->
</ResponseAssertion>
<hashTree/>
<!-- 2. 응답 본문 문자열 포함 검증 -->
<ResponseAssertion testname="Body Contains products">
<collectionProp name="Asserion.test_strings">
<stringProp>"products"</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<intProp name="Assertion.test_type">2</intProp> <!-- contains -->
</ResponseAssertion>
<hashTree/>
<!-- 3. JSON Path Assertion: 특정 필드 검증 -->
<JSONPathAssertion testname="Has total field">
<stringProp name="JSON_PATH">$.total</stringProp>
<boolProp name="JSONVALIDATION">false</boolProp>
<boolProp name="EXPECT_NULL">false</boolProp>
</JSONPathAssertion>
<hashTree/>
<!-- 4. Duration Assertion: 응답시간 500ms 미만 -->
<DurationAssertion testname="Response Time < 500ms">
<longProp name="DurationAssertion.duration">500</longProp>
</DurationAssertion>
<hashTree/>
</hashTree>
</hashTree>
4CLI Non-GUI 자동화 — HTML 리포트 생성
GUI 없이 커맨드라인으로 테스트를 실행하고 HTML 리포트를 자동 생성하는 패턴입니다. CI/CD 파이프라인에 통합하기 위한 필수 패턴입니다.
run_jmeter.sh — Non-GUI 실행 + HTML 리포트
JMX 파일을 커맨드라인으로 실행하고 Grafana Dashboard 수준의 HTML 리포트를 자동 생성하는 쉘 스크립트.
bash#!/bin/bash
# run_jmeter.sh — JMeter CLI 자동화 스크립트
JMETER_HOME="/opt/apache-jmeter-5.6"
JMX_FILE="tests/load_test.jmx"
RESULTS_DIR="results/$(date +%Y%m%d_%H%M%S)"
REPORT_DIR="$RESULTS_DIR/html_report"
mkdir -p "$RESULTS_DIR"
echo "=== JMeter 부하 테스트 시작: $(date) ==="
# Non-GUI 실행
"$JMETER_HOME/bin/jmeter" \
-n \
-t "$JMX_FILE" \
-l "$RESULTS_DIR/results.jtl" \
-e \
-o "$REPORT_DIR" \
-Jthreads=100 \
-Jrampup=30 \
-Jduration=300 \
-JBASE_URL="${BASE_URL:-httpbin.org}"
EXIT_CODE=$?
echo "=== 테스트 완료: exit code $EXIT_CODE ==="
echo "HTML 리포트: $REPORT_DIR/index.html"
# 에러율 체크 (jtl 파일에서 파싱)
ERROR_COUNT=$(grep ",false," "$RESULTS_DIR/results.jtl" | wc -l)
TOTAL_COUNT=$(grep -v "timeStamp" "$RESULTS_DIR/results.jtl" | wc -l)
if [ "$TOTAL_COUNT" -gt 0 ]; then
ERROR_RATE=$(echo "scale=2; $ERROR_COUNT * 100 / $TOTAL_COUNT" | bc)
echo "에러율: ${ERROR_RATE}%"
if (( $(echo "$ERROR_RATE > 5" | bc -l) )); then
echo "❌ 에러율 5% 초과 — 빌드 실패"
exit 1
fi
fi
exit $EXIT_CODE
프로퍼티 전달:
-Jthreads=100처럼 -J 접두사로 JMX 내 ${threads} 변수를 런타임에 오버라이드할 수 있습니다. CI 환경별로 다른 부하 수준을 적용할 때 유용합니다.5분산 테스트 설정 — Controller + Agent
단일 머신의 한계를 넘어 여러 Agent 서버에서 동시에 부하를 발생시키는 분산 테스트 구성입니다.
jmeter.properties — 분산 테스트 설정
Controller에서 여러 Agent 서버로 테스트를 배포하는 분산 구성. 수천 VU 테스트에 필수.
properties# jmeter.properties (Controller 설정)
# Agent 서버 IP 목록 (쉼표 구분)
remote_hosts=192.168.1.101:1099,192.168.1.102:1099,192.168.1.103:1099
# RMI 설정
server.rmi.ssl.disable=true
client.rmi.localport=4000
# 결과 수집 최적화
summariser.name=summary
summariser.interval=30
summariser.log=true
docker-compose.yml — JMeter Controller + Agent
Docker Compose로 Controller 1대 + Agent 3대 분산 환경을 로컬에서 즉시 구성.
yamlversion: '3.8'
services:
jmeter-controller:
image: justb4/jmeter:5.6
container_name: jmeter-controller
volumes:
- ./tests:/tests
- ./results:/results
networks:
- jmeter-net
command: >
-n -t /tests/load_test.jmx
-l /results/results.jtl
-e -o /results/html
-R jmeter-agent1,jmeter-agent2,jmeter-agent3
depends_on:
- jmeter-agent1
- jmeter-agent2
- jmeter-agent3
jmeter-agent1:
image: justb4/jmeter:5.6
container_name: jmeter-agent1
networks:
jmeter-net:
aliases: [jmeter-agent1]
command: -s -Jserver.rmi.ssl.disable=true
jmeter-agent2:
image: justb4/jmeter:5.6
container_name: jmeter-agent2
networks:
jmeter-net:
aliases: [jmeter-agent2]
command: -s -Jserver.rmi.ssl.disable=true
jmeter-agent3:
image: justb4/jmeter:5.6
container_name: jmeter-agent3
networks:
jmeter-net:
aliases: [jmeter-agent3]
command: -s -Jserver.rmi.ssl.disable=true
networks:
jmeter-net:
driver: bridge
실행:
docker-compose up --abort-on-container-exit로 Controller가 종료되면 전체가 같이 내려옵니다. 결과는 ./results/html/index.html에서 확인하세요. JMeter 완전 가이드에서 더 많은 설정을 확인할 수 있습니다.