Performance Testing Methodology
성능 엔지니어링의 전체 체계 — 큰 개념에서 작은 개념으로
📌 이 글의 범위: 성능 테스트 방법론(Load, Stress, Soak 등 테스트 유형과 프로세스)은 소프트웨어(웹/API)와 인프라(네트워크/스토리지/OS) 모두에 공통 적용됨. 달라지는 것은 적용 대상, 메트릭, 도구뿐임. 이 글에서는 두 영역을 모두 다룸.
🎯 전체 구조: 어디에 위치하는가
부하테스트(Load Testing)는 독립된 개념이 아니라, Performance Engineering이라는 큰 틀 안에 속함. 전체 체계를 먼저 이해해야 각 테스트의 목적과 위치가 명확해짐.
flowchart TB PE["Performance Engineering<br/>(성능 엔지니어링)"] subgraph Activities["활동 영역"] direction TB PA["Performance Analysis<br/>(성능 분석)"] PT["Performance Testing<br/>(성능 테스트)"] PO["Performance Tuning<br/>(성능 최적화)"] PM["Performance Monitoring<br/>(성능 모니터링)"] end PE --> Activities PA --> PT PT --> PO PO --> PM PM -->|"피드백"| PA
| 영역 | 설명 | 시점 |
|---|---|---|
| Performance Analysis | 요구사항 분석, SLA/SLO 정의, 병목 예측 | 설계 단계 |
| Performance Testing | 실제 부하를 가하여 시스템 동작 검증 | 개발/배포 단계 |
| Performance Tuning | 테스트 결과를 기반으로 병목 제거, 최적화 | 테스트 후 |
| Performance Monitoring | 운영 환경에서 지속적 성능 관찰 | 운영 단계 |
💡 이 글은 Performance Testing 영역에 집중함. Tuning과 Monitoring은 별도 주제.
📊 Level 1: Performance Testing의 위치와 적용 범위
Performance Testing(성능 테스트) 은 비기능 요구사항(Non-Functional Requirements) 을 검증하는 활동임. 소프트웨어 테스트의 한 분야로 출발했지만, 동일한 방법론이 인프라 전반에 적용됨.
flowchart TB PT["Performance Testing<br/>(성능 테스트)"] subgraph SW["소프트웨어 영역"] Web["Web / API"] WAS["WAS (Tomcat, etc.)"] DB_APP["DB 쿼리 성능"] end subgraph Infra["인프라 영역"] Storage["Storage (Disk I/O)"] Network["Network (대역폭)"] Compute["CPU / Memory"] DB_Engine["DB 엔진 성능"] end PT --> SW PT --> Infra
소프트웨어 vs 인프라 성능 테스트
| 구분 | 소프트웨어 (Web/API) | 인프라 (OS/Network/Storage) |
|---|---|---|
| 질문 | ”요청에 얼마나 빨리 응답하는가?" | "리소스가 얼마나 버티는가?” |
| 부하 단위 | VU (가상 사용자), RPS | iodepth, 대역폭, 스레드 수 |
| 핵심 메트릭 | Response Time, Throughput, Error Rate | IOPS, Bandwidth, Latency, Packet Loss |
| 도구 | k6, JMeter, wrk | fio, iperf3, sysbench |
| 환경 | 운영과 유사한 환경 | 독립된 벤치마크 환경 |
| 방법론 | Load, Stress, Soak… | 동일 |
💡 방법론은 공통임. 이 글에서 설명하는 테스트 유형(Load, Stress, Soak 등)은 대상이 웹이든 스토리지든 네트워크든 동일하게 적용됨. 달라지는 것은 “부하”의 단위와 “측정”의 대상뿐임.
기능 테스트 vs 성능 테스트
| 구분 | 기능 테스트 | 성능 테스트 |
|---|---|---|
| 질문 | ”정상 동작하는가?" | "얼마나 빠르고 안정적인가?” |
| 관심사 | 입출력 정확성 | 응답 시간, 처리량, 안정성 |
| 사용자 수 | 보통 1명 | 수십~수만 명 동시 |
| 환경 | 개발/스테이징 | 운영과 유사한 환경 |
| 측정 대상 | Pass/Fail | 메트릭 (수치) |
📊 Level 2: Performance Testing의 세분화
Performance Testing은 부하 패턴과 목적에 따라 여러 유형으로 나뉨. 각 유형은 서로 다른 질문에 답함.
flowchart TB PT["Performance Testing<br/>(성능 테스트)"] subgraph Baseline["기준선 확립"] Smoke["Smoke Test<br/>기본 동작 확인"] Benchmark["Benchmark Test<br/>기준 성능 측정"] end subgraph Capacity["용량/부하 검증"] Load["Load Test<br/>예상 부하 검증"] Stress["Stress Test<br/>한계점 확인"] Breakpoint["Breakpoint Test<br/>정확한 최대치 탐색"] Scalability["Scalability Test<br/>확장성 검증"] end subgraph Stability["안정성 검증"] Soak["Soak/Endurance Test<br/>장시간 안정성"] Spike["Spike Test<br/>급격한 트래픽 대응"] Recovery["Recovery Test<br/>장애 후 복구"] end PT --> Baseline PT --> Capacity PT --> Stability
💡 아래 각 유형은 소프트웨어와 인프라 양쪽 예시를 함께 제시함.
2-1. Smoke Test (연기 테스트)
질문: “최소 부하에서 시스템이 정상 동작하는가?”
가장 기본적인 테스트. 본격적인 부하테스트 전에 환경, 스크립트, 대상이 정상인지 확인하는 용도.
xychart-beta title "Smoke Test — 부하 패턴" x-axis "시간(분)" [0, 1, 2, 3, 4, 5] y-axis "부하 수준" 0 --> 10 line [0, 3, 5, 5, 3, 0]
| 항목 | 내용 |
|---|---|
| 목적 | 테스트 환경/스크립트 검증, 베이스라인 확보 |
| 부하 | 최소 수준 |
| 시간 | 1~5분 |
| 성공 기준 | 에러 없음, 응답 정상 |
| 언제 | 모든 테스트 전 첫 단계 |
적용 예시:
| 대상 | Smoke Test 내용 |
|---|---|
| 웹/API | 1~5 VU로 주요 엔드포인트 호출, 200 응답 확인 |
| 스토리지 | fio로 iodepth=1, 4K Random Read 1분 실행, I/O 에러 없음 확인 |
| 네트워크 | iperf3로 1Gbps 30초 전송, 패킷 손실 0% 확인 |
2-2. Benchmark Test (벤치마크 테스트)
질문: “현재 시스템의 기준 성능은 얼마인가?”
변경 전/후를 비교하기 위한 기준점(baseline)을 측정. Smoke보다 부하를 약간 높여 안정적인 성능 수치를 확보.
| 항목 | 내용 |
|---|---|
| 목적 | 기준 성능 수치 확보 (비교 대상) |
| 부하 | 예상 평균의 50% 수준 |
| 시간 | 5~15분 |
| 성공 기준 | 안정적인 메트릭 수집 |
| 언제 | 인프라 변경, 코드 배포, 하드웨어 교체 전후 |
적용 예시:
| 대상 | Benchmark Test 내용 |
|---|---|
| 웹/API | 50 VU로 주요 API 10분 실행, p95 응답 시간 기록 |
| 스토리지 | fio 4K/128K Mixed R/W, iodepth=32로 기준 IOPS/Latency 측정 |
| CPU | sysbench cpu —threads=4 로 초당 이벤트 수 기록 |
| DB | pgbench -c 10 -T 300 으로 기준 TPS 측정 |
2-3. Load Test (부하 테스트)
질문: “예상 부하에서 시스템이 SLA를 만족하는가?”
가장 일반적인 성능 테스트. 예상되는 운영 수준의 부하를 시뮬레이션하여 정상 범위에서의 성능을 확인.
xychart-beta title "Load Test — 부하 패턴" x-axis "시간(분)" [0, 5, 10, 15, 20, 25, 30] y-axis "부하 수준" 0 --> 200 line [0, 50, 100, 100, 100, 50, 0]
| 항목 | 내용 |
|---|---|
| 목적 | 정상 운영 조건에서 SLA 충족 여부 확인 |
| 부하 | 예상 운영 수준 |
| 패턴 | Ramp-up → Plateau (유지) → Ramp-down |
| 시간 | 15~60분 |
| 성공 기준 | 성능 메트릭 ≤ SLA 기준, 에러율 < 임계값 |
| 언제 | 배포 전, 정기 검증 |
핵심 패턴 — Ramp-up / Plateau / Ramp-down:
부하
↑
│ ┌──────────────────┐
│ /│ Plateau │\
│ / │ (목표 부하 유지) │ \
│ / │ │ \
│ / │ │ \
│ / │ │ \
│ / │ │ \
├──/──────┴──────────────────┴──────\──→ 시간
Ramp-up Ramp-down
💡 Ramp-up을 왜 하는가? 갑자기 전체 부하를 걸면 Cold Start, 커넥션 풀 초기화, 캐시 미적중 등의 영향으로 실제 운영과 다른 결과가 나옴. 점진적으로 증가시켜야 현실적인 측정이 가능.
적용 예시:
| 대상 | Load Test 내용 |
|---|---|
| 웹/API | 예상 동시 사용자 100 VU, 30분 유지. p95 < 300ms, 에러율 < 0.5% |
| 스토리지 | 운영 예상 워크로드(70% Read / 30% Write, 8K block) 30분 유지, IOPS/Latency 확인 |
| 네트워크 | 예상 트래픽 5Gbps를 30분 유지, Packet Loss < 0.01% |
| DB | 예상 동시 커넥션 50개로 OLTP 워크로드 30분, TPS/Query Latency 확인 |
2-4. Stress Test (스트레스 테스트)
질문: “시스템의 한계는 어디인가? 과부하 시 어떻게 동작하는가?”
예상 부하를 초과하는 수준까지 점진적으로 올려, 성능 저하가 시작되는 지점과 시스템 동작을 확인.
xychart-beta title "Stress Test — 부하 패턴" x-axis "시간(분)" [0, 5, 10, 15, 20, 25, 30, 35, 40] y-axis "부하 수준" 0 --> 500 line [0, 50, 100, 200, 300, 400, 500, 250, 0]
| 항목 | 내용 |
|---|---|
| 목적 | 한계점 파악, 과부하 시 동작 확인, 복구 능력 검증 |
| 부하 | 예상의 150%~300%까지 점진 증가 |
| 패턴 | 계단식(Step) 증가 또는 점진적 증가 |
| 시간 | 20~60분 |
| 관찰 포인트 | 성능 저하 시작점, 에러 발생 시점, 복구 시간 |
| 언제 | 피크 시즌 대비, 인프라 용량 산정 |
적용 예시:
| 대상 | Stress Test 내용 |
|---|---|
| 웹/API | VU를 100 → 200 → 300 → 500 단계적 증가, 에러/타임아웃 시작점 확인 |
| 스토리지 | iodepth를 1 → 16 → 64 → 128 → 256 증가, IOPS 정체 지점 = 한계 |
| 네트워크 | 대역폭을 2G → 5G → 8G → 10G 증가, Packet Loss 발생 시작점 확인 |
| CPU | stress-ng —cpu N, 스레드를 코어 수의 1x → 2x → 4x 증가 |
Load Test vs Stress Test:
flowchart LR subgraph Load["Load Test"] L1["예상 범위 내에서<br/>'잘 동작하는지' 확인"] end subgraph Stress["Stress Test"] S1["예상 범위를 넘어서<br/>'어디까지 버티는지' 확인"] end Load -->|"부하 초과"| Stress
2-5. Spike Test (스파이크 테스트)
질문: “갑작스러운 부하 폭증에 시스템이 버티는가?”
Ramp-up 없이 순간적으로 극단적 부하를 가하여 시스템의 반응을 확인.
xychart-beta title "Spike Test — 부하 패턴" x-axis "시간(분)" [0, 1, 2, 3, 4, 5, 6, 7, 8] y-axis "부하 수준" 0 --> 1000 line [10, 10, 1000, 1000, 10, 10, 1000, 10, 10]
| 항목 | 내용 |
|---|---|
| 목적 | 급격한 부하 폭증 대응력 확인 |
| 부하 | 정상의 5x~10x 이상, 순간 투입 |
| 패턴 | Ramp-up 없이 즉시 최대치 → 즉시 감소 (반복 가능) |
| 시간 | 5~15분 |
| 관찰 포인트 | Auto-scaling 반응 시간, 에러율, 복구 속도 |
| 언제 | 이벤트 전, Auto-scaling 검증 |
적용 예시:
| 대상 | Spike Test 내용 |
|---|---|
| 웹/API | 10 VU → 1000 VU 즉시 투입 (티켓팅, 블랙프라이데이 시뮬레이션) |
| 스토리지 | 유휴 상태에서 갑자기 iodepth=256 Random Write 폭발 (백업 시작 시뮬레이션) |
| 네트워크 | 1Gbps → 10Gbps 즉시 전환 (DDoS, 트래픽 폭증 시뮬레이션) |
Stress vs Spike 차이:
| 구분 | Stress Test | Spike Test |
|---|---|---|
| 증가 방식 | 점진적 (Ramp-up) | 즉각적 (0 → MAX) |
| 목적 | 한계점 파악 | 순간 폭증 대응력 |
| 지속 시간 | 각 단계를 유지 | 매우 짧은 피크 |
| SW 사례 | 피크 시즌 (설 연휴 트래픽) | 티켓팅, 선착순 |
| 인프라 사례 | 서버 증설 시 용량 산정 | 백업/배치 작업 폭발, DDoS |
2-6. Soak / Endurance Test (내구성 테스트)
질문: “장시간 운영 시 시스템이 안정적으로 유지되는가?”
보통 수준의 부하를 장시간(8시간~수일) 유지하여, 시간이 지남에 따라 발생하는 문제를 탐지.
xychart-beta title "Soak Test — 부하 패턴" x-axis "시간" ["0h", "1h", "2h", "4h", "6h", "8h", "9h", "10h"] y-axis "부하 수준" 0 --> 150 line [0, 50, 100, 100, 100, 100, 50, 0]
| 항목 | 내용 |
|---|---|
| 목적 | 장시간 안정성 검증 (리소스 고갈 탐지) |
| 부하 | 예상 평균 부하 수준 (높지 않음) |
| 패턴 | Ramp-up → 장시간 유지 → Ramp-down |
| 시간 | 8시간 ~ 72시간 |
| 관찰 포인트 | 리소스 사용량 추이, 성능 메트릭 변화 |
| 언제 | 장기 운영 서비스 출시 전, 주요 변경 후 |
적용 예시:
| 대상 | Soak Test 내용 |
|---|---|
| 웹/API | 평균 VU로 24시간 유지, 메모리 누수/커넥션 풀 고갈 여부 관찰 |
| 스토리지 | 운영 워크로드로 48시간 연속 I/O, Latency 증가/에러 발생 여부 관찰 |
| 네트워크 | 8Gbps 트래픽을 24시간 유지, Packet Loss/Jitter 추이 관찰 |
| DB | 동시 커넥션 유지 + 주기적 쿼리 24시간, 슬로우 쿼리 발생 추이 관찰 |
Soak에서 발견되는 대표적 문제:
| 문제 | 증상 | SW 원인 | 인프라 원인 |
|---|---|---|---|
| 메모리 누수 | 메모리 사용량 지속 증가 | 객체 미해제, 캐시 무한 성장 | 커널 slab 캐시 누적 |
| 커넥션 풀 고갈 | 응답 시간 점진적 증가 | DB 커넥션 반환 안 됨 | TIME_WAIT 소켓 누적 |
| 디스크 부족 | 로그 적재로 디스크 풀 | 로그 로테이션 미설정 | 임시 파일/코어 덤프 누적 |
| 파일 디스크립터 고갈 | 새 연결 불가 | 소켓 미정리 | ulimit 설정 부족 |
| 성능 저하 | Latency 점진 증가 | GC 빈도 증가 | 디스크 단편화, SSD wear |
2-7. Breakpoint Test (한계점 테스트)
질문: “정확히 어디까지 수용 가능한가?”
Stress Test와 유사하지만 목적이 다름. 정확한 수치를 찾기 위해 더 세밀하게 단계를 올림.
| 항목 | 내용 |
|---|---|
| 목적 | 정확한 최대 수용량(Capacity) 수치 확보 |
| 패턴 | 소폭씩 계단식 증가 |
| 성공 기준 | SLA 기준 위반 직전의 수치 기록 |
| 언제 | 용량 계획(Capacity Planning), 인프라 비용 산정 |
적용 예시:
| 대상 | Breakpoint Test 내용 |
|---|---|
| 웹/API | 10 VU씩 증가, p95 > SLA인 시점의 VU 수 기록 |
| 스토리지 | iodepth를 4씩 증가, IOPS가 포화되는 정확한 지점 측정 |
| 네트워크 | 500Mbps씩 증가, Packet Loss > 0%인 시점의 대역폭 기록 |
2-8. Scalability Test (확장성 테스트)
질문: “리소스를 추가하면 성능이 비례하여 향상되는가?”
수평 확장(Scale-out) 또는 수직 확장(Scale-up) 시 실제 성능 향상 비율을 측정.
| 항목 | 내용 |
|---|---|
| 목적 | 확장 효율성 검증 (2배 리소스 → 2배 성능?) |
| 방법 | 동일 부하를 다른 인프라 규모로 반복 테스트 |
| 관찰 포인트 | 선형 확장 여부, 병목 지점 |
| 언제 | Auto-scaling 정책 수립, 아키텍처 설계 |
적용 예시:
| 대상 | Scalability Test 내용 |
|---|---|
| 웹/API | WAS 인스턴스 1→2→4대에서 동일 부하, RPS가 비례 증가하는지 |
| 스토리지 | RAID 디스크 2→4→8개에서 동일 워크로드, IOPS 향상 비율 |
| 네트워크 | NIC bonding 1→2→4에서 대역폭 선형 증가 여부 |
| DB | Read Replica 1→3→5에서 동일 쿼리 부하, QPS 향상 비율 |
2-9. Recovery Test (복구 테스트)
질문: “장애 후 시스템이 얼마나 빨리 정상으로 돌아오는가?”
과부하로 장애를 유발한 뒤 부하를 낮춰서, 시스템이 자동으로 복구되는지 확인.
| 항목 | 내용 |
|---|---|
| 목적 | 장애 복구 능력, Mean Time To Recovery (MTTR) 측정 |
| 패턴 | 과부하 → 장애 유발 → 부하 감소 → 복구 관찰 |
| 관찰 포인트 | 복구 시간, 데이터 손실 여부, 큐 소진 시간 |
| 언제 | DR(Disaster Recovery) 검증, SLA 복구 시간 확인 |
적용 예시:
| 대상 | Recovery Test 내용 |
|---|---|
| 웹/API | OOM 유발 후 WAS 자동 재시작 시간, 요청 큐 소진 시간 |
| 스토리지 | 디스크 풀 유발 후 공간 확보 시 I/O 정상화 시간 |
| 네트워크 | 링크 다운 후 failover 전환 시간, 패킷 손실 복구 시간 |
| DB | 커넥션 풀 고갈 후 회수 시 정상 TPS 복구 시간 |
📊 Level 3: 전체 유형 비교
한눈에 비교
| 유형 | 부하 수준 | 시간 | 핵심 질문 | 우선순위 |
|---|---|---|---|---|
| Smoke | 매우 낮음 | 분 | 기본 동작 OK? | ⭐⭐⭐ (항상) |
| Load | 예상 수준 | 15~60분 | SLA 충족? | ⭐⭐⭐ (필수) |
| Stress | 예상 초과 | 20~60분 | 한계는? | ⭐⭐⭐ (필수) |
| Spike | 극단적 | 분 | 폭증 대응? | ⭐⭐ (이벤트성) |
| Soak | 보통 | 시간~일 | 장기 안정? | ⭐⭐ (운영 전) |
| Breakpoint | 점진 최대 | 30~60분 | 정확한 한계치? | ⭐⭐ (용량 산정) |
| Scalability | 가변 | 가변 | 확장 효율? | ⭐ (아키텍처 검증) |
| Recovery | 과부하→감소 | 가변 | 복구 시간? | ⭐ (DR 검증) |
실행 순서 (권장)
flowchart LR S1["1. Smoke<br/>환경 검증"] S2["2. Benchmark<br/>기준선 확보"] S3["3. Load<br/>SLA 검증"] S4["4. Stress<br/>한계 확인"] S5["5. Spike/Soak<br/>시나리오별"] S6["6. 결과 분석<br/>& 튜닝"] S1 --> S2 --> S3 --> S4 --> S5 --> S6 S6 -->|"재테스트"| S3
💡 반드시 순서대로. Smoke 없이 Load를 돌리면 환경 문제인지 성능 문제인지 구분이 안 됨. Load 없이 Stress를 돌리면 정상 범위 기준이 없어 결과 해석이 불가능함. 이 순서는 웹이든 인프라든 동일함.
📏 Level 4: 핵심 메트릭 (무엇을 측정하는가)
성능 테스트의 결과는 메트릭으로 표현됨. 대상에 따라 메트릭이 달라짐.
소프트웨어 메트릭 (Web/API)
외부 (사용자 관점):
| 메트릭 | 설명 | 좋은 기준 (일반 웹) |
|---|---|---|
| Response Time | 요청 → 응답까지 걸린 시간 | p50 < 200ms, p95 < 500ms, p99 < 1s |
| Throughput (RPS) | 초당 처리 요청 수 (Requests Per Second) | 시스템 목표에 따라 다름 |
| Error Rate | 전체 요청 중 에러(4xx, 5xx) 비율 | < 0.1% (정상), < 1% (허용) |
| Availability | 전체 시간 중 정상 서비스 비율 | 99.9% (3 nines), 99.99% (4 nines) |
내부 (시스템 관점):
| 메트릭 | 설명 | 관찰 대상 |
|---|---|---|
| CPU Utilization | CPU 사용률 | 80% 이상 → 경고 |
| Memory Usage | 메모리 사용량/사용률 | Soak에서 지속 증가 → 누수 |
| DB Connections | DB 커넥션 풀 사용량 | 풀 고갈 시 타임아웃 |
| Thread Count | 활성 스레드 수 | WAS의 스레드 풀 |
| GC (Garbage Collection) | JVM GC 빈도/시간 | Java/Kotlin 기반 WAS |
인프라 메트릭
| 대상 | 핵심 메트릭 | 설명 | 도구 |
|---|---|---|---|
| 스토리지 (Disk) | IOPS | 초당 I/O 작업 수 (Read/Write) | fio, dd |
| Throughput (MB/s) | 초당 전송량 | fio | |
| Latency | I/O 요청당 지연 시간 | fio, iostat | |
| 네트워크 | Bandwidth | 최대 전송 대역폭 (Gbps) | iperf3 |
| Latency / Jitter | 지연 시간 및 변동성 | ping, mtr | |
| Packet Loss | 패킷 손실률 | iperf3, ping | |
| CPU | 연산 성능 | 싱글/멀티 스레드 처리 능력 | sysbench, stress-ng |
| 메모리 | Bandwidth (GB/s) | 메모리 읽기/쓰기 속도 | sysbench, mbw |
| Latency (ns) | 메모리 접근 지연 | Intel MLC | |
| DB 엔진 | QPS / TPS | 초당 쿼리/트랜잭션 수 | sysbench, pgbench |
| Query Latency | 쿼리별 응답 시간 | slow query log |
메트릭 간의 관계
flowchart TB subgraph External["외부 메트릭 (SW)"] RT["Response Time<br/>(p50, p95, p99)"] RPS["Throughput<br/>(RPS)"] ERR["Error Rate"] end subgraph Internal["내부 메트릭 (공통)"] CPU["CPU"] MEM["Memory"] DISK["Disk I/O<br/>(IOPS, Latency)"] NET["Network I/O<br/>(Bandwidth, Loss)"] DB["DB<br/>(Connections, QPS)"] end External -->|"느려지면 원인 추적"| Internal DISK -->|"I/O 병목"| RT NET -->|"대역폭 포화"| RT CPU -->|"연산 병목"| RPS DB -->|"쿼리 지연"| RT
💡 소프트웨어 성능 문제의 근본 원인은 결국 인프라 메트릭에서 드러남. 웹 응답이 느리다면 → CPU 포화? 디스크 I/O 병목? DB 쿼리 지연? 네트워크 포화? 를 추적하게 됨.
백분위수(Percentile)가 중요한 이유
평균(Avg)은 거짓말한다:
사용자 A: 100ms
사용자 B: 100ms
사용자 C: 100ms
사용자 D: 100ms
사용자 E: 5000ms ← 타임아웃 직전
평균: 1080ms → "1초 정도네"
p50: 100ms → "절반은 100ms 이내"
p95: 5000ms → "20명 중 1명은 5초 대기" ← 이게 실체
💡 p95, p99를 봐야 함. 평균은 극단값을 숨김. SLA도 보통 “p95 응답 시간 500ms 이내” 같은 형태로 정의함. 이는 인프라 메트릭에서도 마찬가지 — fio 결과의 p99 Latency가 평균과 크게 벌어지면 I/O 지터가 존재하는 것.
📏 Level 5: SLA / SLO / SLI
성능 테스트의 합격/불합격 기준은 SLA/SLO에서 나옴.
flowchart TB SLA["SLA (Service Level Agreement)<br/>고객과의 계약<br/>'월 99.9% 가용성 보장, 미달 시 크레딧 지급'"] SLO["SLO (Service Level Objective)<br/>내부 목표<br/>'p95 응답 시간 200ms 이내'"] SLI["SLI (Service Level Indicator)<br/>실제 측정값<br/>'현재 p95 = 180ms'"] SLA -->|"기반"| SLO SLO -->|"측정"| SLI SLI -->|"충족 여부 판단"| SLO
| 개념 | 설명 | SW 예시 | 인프라 예시 |
|---|---|---|---|
| SLA | 고객/비즈니스와의 약속 (위반 시 페널티) | “월 99.9% 가용성, 위반 시 10% 크레딧" | "스토리지 IOPS 10,000 이상 보장” |
| SLO | 내부 운영 목표 (SLA보다 엄격하게 설정) | “p95 응답 시간 200ms" | "디스크 p99 Latency < 1ms” |
| SLI | 실제 측정 지표 | ”현재 p95 = 180ms" | "현재 p99 Latency = 0.8ms” |
💡 SLO를 SLA보다 엄격하게 설정해야 SLA 위반 전에 대응할 수 있음. 예: SLA가 “p95 < 500ms”면, SLO는 “p95 < 300ms”으로 설정.
🔄 Level 6: 성능 테스트 프로세스
전체 라이프사이클
flowchart TB P1["1. 요구사항 분석<br/>SLA/SLO 정의"] P2["2. 테스트 계획<br/>범위, 환경, 시나리오"] P3["3. 환경 준비<br/>테스트 환경 구축"] P4["4. 스크립트 작성<br/>테스트 시나리오 구현"] P5["5. 테스트 실행<br/>Smoke → Load → Stress"] P6["6. 결과 분석<br/>메트릭 분석, 병목 식별"] P7["7. 튜닝 & 재테스트<br/>최적화 후 재검증"] P8["8. 보고서 작성<br/>결과 문서화"] P1 --> P2 --> P3 --> P4 --> P5 --> P6 P6 -->|"병목 발견"| P7 P7 -->|"재테스트"| P5 P6 -->|"통과"| P8
1단계: 요구사항 분석
시작 전에 반드시 정의해야 할 것:
소프트웨어 (Web/API):
| 항목 | 질문 | 예시 |
|---|---|---|
| 대상 시스템 | 무엇을 테스트하는가? | 주문 API, 로그인 페이지 |
| 예상 사용자 | 동시 접속자는 몇 명? | 평일 100명, 피크 500명 |
| SLO 정의 | 합격 기준은? | p95 < 300ms, 에러율 < 0.5% |
| 핵심 시나리오 | 가장 중요한 사용자 흐름은? | 로그인 → 검색 → 주문 |
| 테스트 유형 | 어떤 유형이 필요한가? | Load + Stress (최소) |
인프라:
| 항목 | 질문 | 예시 |
|---|---|---|
| 대상 리소스 | 무엇을 테스트하는가? | NVMe SSD, 10GbE NIC, DB 서버 |
| 예상 워크로드 | 운영 시 예상 부하는? | 4K Random R/W 70:30, 일일 500GB 전송 |
| SLO 정의 | 합격 기준은? | IOPS > 50,000, p99 Latency < 1ms |
| 핵심 패턴 | 가장 빈번한 I/O 패턴은? | 4K Random Read (DB), 128K Sequential Write (로그) |
| 테스트 유형 | 어떤 유형이 필요한가? | Benchmark + Stress + Soak |
2단계: 테스트 계획
소프트웨어 테스트 계획 (예시):
테스트 계획 문서:
├── 1. 목적 및 범위
├── 2. 테스트 환경 (서버 스펙, 네트워크)
├── 3. 테스트 시나리오
│ ├── 시나리오 1: 로그인 + 메인 페이지
│ ├── 시나리오 2: 상품 검색 + 상세 보기
│ └── 시나리오 3: 장바구니 + 주문
├── 4. 부하 모델 (VU 수, Ramp-up, 시간)
├── 5. 성공 기준 (SLO)
├── 6. 모니터링 항목
├── 7. 일정
└── 8. 리스크/제약사항
인프라 테스트 계획 (예시):
테스트 계획 문서:
├── 1. 목적 및 범위
├── 2. 테스트 환경 (하드웨어 스펙, 펌웨어 버전)
├── 3. 테스트 시나리오
│ ├── 시나리오 1: 스토리지 — 4K Random R/W, 128K Sequential
│ ├── 시나리오 2: 네트워크 — TCP/UDP 대역폭, Latency
│ └── 시나리오 3: DB — OLTP 워크로드, 동시 커넥션
├── 4. 부하 모델 (iodepth, 대역폭, 동시 스레드)
├── 5. 성공 기준 (IOPS, Bandwidth, Latency)
├── 6. 모니터링 항목 (iostat, vmstat, sar)
├── 7. 일정
└── 8. 리스크/제약사항
3단계: 환경 준비
| 원칙 | SW 적용 | 인프라 적용 |
|---|---|---|
| 운영과 유사 | 서버 스펙, 데이터 크기 일치 | 동일 하드웨어, 동일 펌웨어 |
| 격리 | 다른 트래픽 영향 없는 환경 | 다른 I/O/네트워크 간섭 없는 환경 |
| 테스트 데이터 | 현실적인 양과 분포 | 운영과 유사한 파일 크기/패턴 |
| 모니터링 | APM, 로그 수집 설정 | iostat, vmstat, sar, dstat 설정 |
4~5단계: 스크립트 작성 & 실행
도구별 실습은 후속 글에서 다룸. → [Performance Testing Tools (예정)]
6단계: 결과 분석
소프트웨어 병목 추적:
flowchart TB Result["테스트 결과"] Result -->|"응답 시간 증가"| Q1["어디서 느려지는가?"] Result -->|"에러율 증가"| Q2["어떤 에러인가?"] Result -->|"처리량 정체"| Q3["병목이 어디인가?"] Q1 --> A1["DB 쿼리? WAS 스레드? 네트워크?"] Q2 --> A2["5xx (서버)? 타임아웃? 커넥션 거부?"] Q3 --> A3["CPU 포화? 메모리 부족? I/O 대기?"] A1 --> Tuning["튜닝 & 재테스트"] A2 --> Tuning A3 --> Tuning
인프라 병목 추적:
flowchart TB Result["테스트 결과"] Result -->|"IOPS 목표 미달"| Q1["어디서 병목인가?"] Result -->|"Latency 증가"| Q2["어떤 구간인가?"] Result -->|"Bandwidth 포화"| Q3["어디가 좁은가?"] Q1 --> A1["디스크 자체? 컨트롤러? 파일시스템?"] Q2 --> A2["디스크 큐 깊이? 네트워크 hop? 스위치?"] Q3 --> A3["NIC? 스위치 포트? ISP?"] A1 --> Tuning["튜닝 & 재테스트"] A2 --> Tuning A3 --> Tuning
🛠️ Level 7: 도구 분류
소프트웨어 성능 테스트 도구
flowchart TB Tools["SW 부하테스트 도구"] subgraph CLI["CLI 경량 도구"] ab["ab (Apache Bench)"] wrk["wrk"] hey["hey"] vegeta["vegeta"] end subgraph Script["스크립트 기반"] k6["k6<br/>(JavaScript)"] locust["Locust<br/>(Python)"] gatling["Gatling<br/>(Scala/Java)"] end subgraph Enterprise["GUI / 엔터프라이즈"] jmeter["JMeter<br/>(Apache)"] loadrunner["LoadRunner<br/>(Micro Focus)"] blazemeter["BlazeMeter<br/>(Perforce)"] ngrinder["nGrinder<br/>(Naver)"] end Tools --> CLI Tools --> Script Tools --> Enterprise
| 도구 | 언어 | 유형 | 분산 테스트 | 프로토콜 | 비용 | 적합 용도 |
|---|---|---|---|---|---|---|
| ab | C | CLI | ❌ | HTTP | 무료 | 빠른 단일 URL 테스트 |
| wrk | C | CLI | ❌ | HTTP | 무료 | 고성능 벤치마크 |
| hey | Go | CLI | ❌ | HTTP | 무료 | ab 대안, 간편 |
| vegeta | Go | CLI | ❌ | HTTP | 무료 | 일정 RPS 부하 |
| k6 | Go (JS 스크립트) | 스크립트 | ✅ (k6 Cloud) | HTTP, WebSocket, gRPC | 무료/유료 | CI/CD 통합, 개발자 친화 |
| Locust | Python | 스크립트 | ✅ (내장) | HTTP, 커스텀 | 무료 | Python 팀, 유연한 시나리오 |
| Gatling | Scala/Java | 스크립트 | ✅ (Enterprise) | HTTP, WebSocket | 무료/유료 | 고성능, 상세 보고서 |
| JMeter | Java | GUI + CLI | ✅ (내장) | HTTP, JDBC, LDAP 등 | 무료 | 다양한 프로토콜, SI 표준 |
| nGrinder | Java/Groovy | GUI | ✅ (내장) | HTTP | 무료 | 네이버 개발, 한국 기업에서 활용 |
| LoadRunner | — | GUI | ✅ | 50+ 프로토콜 | 유료 (고가) | 엔터프라이즈, 대규모 |
| BlazeMeter | — | SaaS | ✅ (클라우드) | HTTP, JMeter 호환 | 유료 | 클라우드 기반, JMeter 확장 |
SW 도구 선택 가이드:
flowchart TB Start["도구 선택"] Start -->|"간단한 벤치마크?"| Q1{"단일 URL?"} Q1 -->|"Yes"| CLI["ab / wrk / hey"] Q1 -->|"No"| Q2 Start -->|"시나리오 테스트?"| Q2{"팀 언어?"} Q2 -->|"JavaScript"| k6_choice["k6"] Q2 -->|"Python"| locust_choice["Locust"] Q2 -->|"Java/Scala"| gatling_choice["Gatling"] Start -->|"GUI 필요?"| Q3{"프로토콜?"} Q3 -->|"HTTP만"| ngrinder_choice["nGrinder"] Q3 -->|"다양한 프로토콜"| jmeter_choice["JMeter"] Start -->|"CI/CD 통합?"| k6_choice
💡 인프라 엔지니어 추천: CLI 도구(wrk/hey)로 빠른 벤치마크 + k6로 시나리오 테스트. 공공 SI에서는 JMeter나 nGrinder가 표준으로 쓰이는 경우가 많음.
인프라 성능 테스트 도구
flowchart TB InfraTools["인프라 성능 테스트 도구"] subgraph Storage["스토리지"] fio["fio"] dd["dd"] bonnie["bonnie++"] end subgraph Network["네트워크"] iperf["iperf3"] mtr["mtr"] netperf["netperf"] end subgraph Compute["CPU / 메모리"] sysbench["sysbench"] stressng["stress-ng"] geekbench["Geekbench"] end subgraph DBEngine["DB 엔진"] pgbench["pgbench<br/>(PostgreSQL)"] mysqlslap["mysqlslap<br/>(MySQL)"] sysbench_db["sysbench<br/>(OLTP)"] end InfraTools --> Storage InfraTools --> Network InfraTools --> Compute InfraTools --> DBEngine
| 도구 | 대상 | 설명 | 주요 메트릭 |
|---|---|---|---|
| fio | 스토리지 | Flexible I/O Tester. 스토리지 벤치마크의 사실상 표준 | IOPS, Bandwidth, Latency |
| dd | 스토리지 | 단순 순차 읽기/쓰기 속도 측정 | Throughput (MB/s) |
| bonnie++ | 스토리지 | 파일시스템 수준 I/O 벤치마크 | 생성/읽기/삭제 성능 |
| iperf3 | 네트워크 | 네트워크 대역폭 측정 (TCP/UDP) | Bandwidth, Jitter, Packet Loss |
| mtr | 네트워크 | traceroute + ping 결합. 구간별 지연 분석 | Latency, Packet Loss per hop |
| netperf | 네트워크 | 네트워크 성능 벤치마크 (TCP/UDP/SCTP) | Throughput, Latency |
| sysbench | CPU/메모리/DB | 다목적 벤치마크. CPU, 메모리, MySQL/PG 테스트 | 연산 속도, QPS, Latency |
| stress-ng | CPU/메모리 | 시스템 스트레스 테스트. 300+ 개 stressor | CPU/MEM/IO 한계 |
| pgbench | PostgreSQL | PG 내장 벤치마크 도구 | TPS, Latency |
| mysqlslap | MySQL | MySQL 내장 벤치마크 도구 | QPS, 응답 시간 |
인프라 도구 선택 가이드:
flowchart TB Start["인프라 도구 선택"] Start -->|"스토리지?"| Q1{"테스트 수준?"} Q1 -->|"간단 속도 체크"| dd_choice["dd"] Q1 -->|"상세 벤치마크"| fio_choice["fio"] Start -->|"네트워크?"| Q2{"무엇을 측정?"} Q2 -->|"대역폭"| iperf_choice["iperf3"] Q2 -->|"구간별 지연"| mtr_choice["mtr"] Start -->|"CPU/메모리?"| sysbench_choice["sysbench / stress-ng"] Start -->|"DB 엔진?"| Q3{"어떤 DB?"} Q3 -->|"PostgreSQL"| pgbench_choice["pgbench"] Q3 -->|"MySQL"| Q4{"간단/상세?"} Q4 -->|"간단"| mysqlslap_choice["mysqlslap"] Q4 -->|"상세 OLTP"| sysbench_db_choice["sysbench"]
💡 인프라 엔지니어 추천: 스토리지는 fio, 네트워크는 iperf3, CPU/DB는 sysbench — 이 3개면 대부분의 인프라 성능 테스트를 커버할 수 있음.
📐 Level 8: 테스트 시나리오 설계
시나리오란?
실제 운영 환경의 워크로드를 모방한 테스트 흐름. 단순히 하나의 요청을 반복하는 것이 아니라 현실적인 패턴을 구성해야 함.
소프트웨어 시나리오 설계
설계 원칙:
| 원칙 | 설명 |
|---|---|
| 현실적 사용자 흐름 | 로그인 → 탐색 → 행동 → 로그아웃 |
| Think Time | 사용자가 페이지를 읽는 대기 시간 포함 (1~5초) |
| 데이터 파라미터화 | 같은 사용자/같은 데이터가 아닌, 다양한 입력 |
| 비율 분배 | 실제 트래픽 비율 반영 (조회 80%, 주문 5% 등) |
| 상관관계 | 응답 값을 다음 요청에 활용 (세션, 토큰) |
시나리오 예시: 쇼핑몰
flowchart LR A["메인 페이지 접속"] --> B["상품 검색"] B --> C["상품 상세 보기<br/>(Think Time 3s)"] C --> D{"구매?"} D -->|"20%"| E["장바구니 추가"] D -->|"80%"| B E --> F["주문/결제"]
| 시나리오 | 사용자 비율 | 설명 |
|---|---|---|
| 단순 조회 (메인 → 검색 → 상세) | 70% | 대부분의 사용자 |
| 장바구니 추가 | 20% | 관심 상품 담기 |
| 주문/결제 | 8% | 실제 구매 |
| 관리자 접속 | 2% | 백오피스 |
인프라 시나리오 설계
설계 원칙:
| 원칙 | 설명 |
|---|---|
| 운영 워크로드 재현 | 실제 I/O 패턴, 블록 크기, R/W 비율 반영 |
| 혼합 워크로드 (Mixed) | 단일 패턴이 아닌, 실제처럼 다양한 I/O 혼합 |
| 워밍업 | 스토리지 캐시/버퍼를 채운 후 측정 (Cold → Warm) |
| 반복 가능성 | 동일 조건으로 재현 가능하도록 파라미터 고정 |
시나리오 예시: 3-Tier 인프라 벤치마크
flowchart TB subgraph Web["Web 서버"] W1["네트워크 테스트<br/>iperf3: 10GbE 대역폭"] end subgraph WAS["WAS 서버"] W2["CPU 테스트<br/>sysbench: 멀티스레드"] W3["메모리 테스트<br/>sysbench: R/W 속도"] end subgraph DB["DB 서버"] D1["스토리지 테스트<br/>fio: 4K Random R/W"] D2["DB 엔진 테스트<br/>pgbench: OLTP TPS"] end Web --> WAS --> DB
| 티어 | 시나리오 | 도구 | 핵심 메트릭 |
|---|---|---|---|
| Web | 10GbE NIC 대역폭 측정 + Latency | iperf3 | Bandwidth, Jitter |
| WAS | CPU 멀티코어 연산 + 메모리 대역폭 | sysbench | Events/s, MB/s |
| DB (스토리지) | 4K Random Read 70% + Write 30%, iodepth=64 | fio | IOPS, p99 Latency |
| DB (엔진) | 동시 커넥션 50, TPC-B 워크로드 30분 | pgbench | TPS, Latency |
스토리지 워크로드 프로파일 (예시):
| 프로파일 | 블록 크기 | 패턴 | R/W 비율 | iodepth | 용도 |
|---|---|---|---|---|---|
| DB (OLTP) | 4K~8K | Random | 70:30 | 32~64 | MySQL, PostgreSQL |
| 로그 수집 | 64K~128K | Sequential | 0:100 (Write) | 1~4 | syslog, 애플리케이션 로그 |
| 파일 서버 | 64K~1M | Sequential | 50:50 | 8~16 | NFS, SMB |
| 가상화 | 4K~64K | Mixed | 60:40 | 16~32 | VM 디스크 이미지 |
📋 용어 정리
공통 용어
| 용어 | 영문 | 설명 |
|---|---|---|
| Ramp-up | Ramp-up Period | 부하를 점진적으로 증가시키는 구간 |
| Plateau | Plateau | 목표 부하를 유지하는 구간 |
| Ramp-down | Ramp-down Period | 부하를 점진적으로 감소시키는 구간 |
| Percentile | Percentile (p50, p95, p99) | 백분위수. p95 = 전체의 95%가 이 값 이하 |
| Throughput | Throughput | 단위 시간당 처리량 |
| Latency | Latency | 지연 시간 |
| Saturation | Saturation | 리소스 포화 상태 |
| Baseline | Baseline | 비교 기준이 되는 성능 수치 |
| Bottleneck | Bottleneck | 전체 성능을 제한하는 병목 지점 |
| SLA/SLO/SLI | Service Level Agreement/Objective/Indicator | 서비스 수준 합의/목표/지표 |
| MTTR | Mean Time To Recovery | 평균 복구 시간 |
소프트웨어 용어
| 용어 | 영문 | 설명 |
|---|---|---|
| VU | Virtual User | 가상 사용자 (동시 접속 시뮬레이션 단위) |
| RPS | Requests Per Second | 초당 요청 수 |
| TPS | Transactions Per Second | 초당 트랜잭션 수 (비즈니스 단위) |
| Think Time | Think Time | 사용자의 사고/대기 시간 (요청 간 간격) |
| Response Time | Response Time | 요청부터 응답까지 걸린 시간 |
| Error Rate | Error Rate | 전체 요청 중 에러 비율 |
인프라 용어
| 용어 | 영문 | 설명 |
|---|---|---|
| IOPS | I/O Operations Per Second | 초당 I/O 작업 수 |
| Bandwidth | Bandwidth | 데이터 전송 대역폭 (MB/s 또는 Gbps) |
| iodepth | I/O Queue Depth | 동시에 대기하는 I/O 요청 수 (큐 깊이) |
| Block Size | Block Size | 한 번의 I/O에서 읽기/쓰기하는 데이터 크기 |
| QPS | Queries Per Second | 초당 쿼리 수 (DB) |
| Packet Loss | Packet Loss | 전송 중 손실된 패킷 비율 |
| Jitter | Jitter | 지연 시간의 변동성 |
🔗 관련 문서
- (예정) Performance Testing Tools — 도구별 실습 (k6, JMeter, wrk, fio, iperf3) →
01. Infra/Performance/ - (예정) Performance Tuning Guide — 병목 분석 및 최적화 →
01. Infra/Performance/ - Apache vs Nginx — 웹서버 성능 비교
- Nginx + Tomcat 연동 — WAS 연동 구조
- Tomcat 설정 — WAS 튜닝 관련
- PMBOK Overview — 프로젝트 관리 방법론
- ITIL Overview — IT 서비스 관리 방법론