이코에코(Eco²) Streams & Scaling for SSE #11: Scan API 부하 테스트 (2)
VU 300 부하 한계점 분석
테스트 데이터 비교 (250 VU vs 300 VU)
| 요청 수 | 1,754 | 1,732 | -22건 (-1.3%) |
| 완료율 | 99.94% | 99.94% | 동일 |
| Throughput | 417.6 req/m | 402 req/m | -0.22 (-3.2%) |
| E2E p95 | 40.5초 | 48.5초 | +8초 (+20%) |
| E2E avg | 30.2초 | 37.6초 | +7.4초 (+25%) |
| 테스트 시간 | 252초 | 256.8초 | +4.8초 |
부하 포화 징후
┌────────────────────────────────────────────────────────────────────────┐
│ 📊 Little's Law 기반 분석 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ 250 VU: Throughput = 250 / 40.5초 = 6.17 req/s (실측 6.96) │
│ 300 VU: Throughput = 300 / 48.5초 = 6.19 req/s (실측 6.74) │
│ │
│ → VU 20% 증가 시 이론적으로 Throughput도 증가해야 함 │
│ → 실제로는 오히려 3.2% 감소 = 처리 시간 증가 관측, 시스템 포화 상태 진입 │
│ │
└────────────────────────────────────────────────────────────────────────┘
포화 판단 근거
- 처리량 역전 현상
- VU 증가(+20%)에도 불구하고 throughput 감소(-3.2%)
- 시스템이 물리적 부하에 도달해 연산량 저하, 더 많은 요청을 받아도 빠르게 처리하지 못함
- 노드 수평 확장 필요, 컴포넌트별 단일 노드 한계 지점 도출을 위해 노드 HA는 적용하지 않음
- 응답 시간 급증
- E2E p95: 40.5초 → 48.5초 (+20%)
- 큐 대기 시간 증가로 인한 지연
- 요청 수 감소
- 같은 3분 동안 22건 더 적게 처리
- 각 VU의 iteration 횟수 감소
- 성공률 유지
- 99.94%로 동일 = 아직 에러 발생 X
- 시스템은 느려지지만 실패하지 않음
로컬 Mac 스펙 분석
시스템 사양
| CPU | Apple M3 |
| 코어 | 8코어 |
| 메모리 | 16 GB |
| FD Limit | 1,048,575 |
k6 클라이언트 VU 한계 추정
| CPU 기반 | 8코어 × 200 VU | 1,600 VU |
| 메모리 기반 | 16GB ÷ 10MB | 1,600 VU |
| FD 기반 | 1M ÷ 10 | 100,000+ VU |
┌────────────────────────────────────────────────────────────────────────┐
│ 🖥️ 로컬 k6 클라이언트 한계: ~1,600 VU │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ ✅ 500 VU 테스트: 문제 없음 │
│ ✅ 1000 VU 테스트: 가능 │
│ ⚠️ 1500+ VU: 주의 필요 │
│ │
│ 💡 현재 병목은 서버 측 (k8s-worker-ai 2 cores) │
│ 로컬 Mac은 충분히 여유 있음 │
│ │
└────────────────────────────────────────────────────────────────────────┘
VU 400 부하 테스트 리포트
https://snapshots.raintank.io/dashboard/snapshot/frzezh23ZWCrpiWNprpEtv3tFsdTEouI
Grafana
If you're seeing this Grafana has failed to load its application files 1. This could be caused by your reverse proxy settings. 2. If you host grafana under subpath make sure your grafana.ini root_url setting includes subpath. If not using a reverse proxy m
snapshots.raintank.io
테스트 환경
- 시간: 2025-12-28 22:46:46 ~ 22:54:40 KST (약 8분)
- VUs: 400 (동시 사용자)
- 테스트 방식: POST → Polling 방식
K6 테스트 결과




| 성공률 | 99.6% (1,894/1,901) | ✅ 1901 요청 중 7건 실패 |
| 완료율 | 98.9% (1,790/1,810) | ✅ 여전히 높음 |
| 보상 수령률 | 95.2% (1,715/1,790) | ⚠️ 소폭 하락 |
| Scan API p95 | 207ms | ⚠️ 증가 (300VU: 83ms) |
| 완료 시간 p95 | 62.0초 | ⚠️ 임계치(60초) 초과 |
| E2E p95 | 62.2초 | ⚠️ 증가 (300VU: 48초) |
| Throughput | 422.2 req/m | ✅ 최고치 |
| Polling 요청 | 36,583건 | 약 20회/job |
KEDA Scaling 이벤트
| 시간 | 이벤트 | 상세 |
|---|---|---|
| 테스트 시작 | scan-worker 1→3 | scan.{vision, answer, rule} 큐 기반 트리거 |
| +24초 | scan-api 1→2 | CPU 사용률 기반 |
| +54초 | scan-api 2→3 | CPU 사용률 기반 |
| 테스트 종료 | scan-worker 3→1 | 메트릭 정상화 |
Redis Streams 상태 (테스트 후)
scan:events:0: 4,860
scan:events:1: 4,700
scan:events:2: 4,970
scan:events:3: 4,410
총: 18,940개 (균등 분배 ±6%)
Pending: 0 (모든 메시지 ACK 완료)
테스트 결과 비교 (50 ~ 400 VU)
| 50 | 685 | 99.7% | 198 req/m | 17.7초 | 93ms | ✅ 여유 |
| 200 | 1,649 | 99.8% | 367 req/m | 33.2초 | 83ms | ✅ 여유 |
| 250 | 1,754 | 99.9% | 417.6 req/m | 40.5초 | 78ms | ⭐ 서비스 최적점(SLA) |
| 300 | 1,732 | 99.9% | 402 req/m | 48.5초 | 83ms | ⚠️ 포화 시작 |
| 400 | 1,901 | 98.9% | 422.2 req/m | 62.2초 | 207ms | ⚠️ 한계 근접 |
┌────────────────────────────────────────────────────────────────────────┐
│ 📊 400 VU 분석 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ ✅ 예상보다 좋은 결과: 98.9% 완료율 (예상 90-95%) │
│ ✅ Throughput 최고치: 7.12 req/s (300VU 대비 +5.6%) │
│ ✅ KEDA 정상 작동: scan-worker 1→3, scan-api 1→3 스케일업 │
│ │
│ ⚠️ 경고 신호: │
│ • E2E p95 62초 (Eco² SLA 임계치 60초 초과) │
│ • Scan API p95 207ms (300VU 대비 2.5배 증가) │
│ • 완료율 98.9% (300VU 99.9% 대비 1% 하락) │
│ • 실패 7건 발생 (300VU: 0건) │
│ │
└────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────┐
│ 🎯 단일 노드 한계점: ~400 VU │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ • 400 VU에서 98.9% 완료율 유지 = 아직 안정적 │
│ • 하지만 E2E p95 > 60초 = SLA 임계치 초과 │
│ • Throughput은 오히려 증가 (7.12 req/s) = KEDA 스케일링 효과 │
│ │
│ 📈 실제 한계: │
│ • 완료율 기준: ~450-500 VU에서 95% 이하로 하락 예상 │
│ • SLA 기준 (E2E p95 < 60초): 300 VU가 안전 한계 │
│ │
│ 🚀 확장 전략: │
│ • Karpenter 적용 시 400 VU × 노드수 확장 가능 │
│ • 현재 단일 노드(2 cores)에서 400 VU 처리 가능 확인 │
│ │
└────────────────────────────────────────────────────────────────────────┘
VU 500 부하 테스트
https://snapshots.raintank.io/dashboard/snapshot/dtBvLo3J2JlQ3LwWbcM6iwBJJuhboow5
Grafana
If you're seeing this Grafana has failed to load its application files 1. This could be caused by your reverse proxy settings. 2. If you host grafana under subpath make sure your grafana.ini root_url setting includes subpath. If not using a reverse proxy m
snapshots.raintank.io
테스트 환경
- 시간: 2025-12-28 23:16:36 ~ 23:21:45 KST (약 5분)
- VUs: 500 (동시 사용자)
- 테스트 방식: POST → Polling 방식
- 환경: 큐/스트림 청정 상태에서 시작
K6 테스트 결과




| 성공률 | 99.7% (1,984/1,990) | ✅ 6건 실패 |
| 완료율 | 94.0% (1,629/1,733) | ⚠️ 95% 이하로 하락 |
| 보상 수령률 | 91.2% (1,575/1,629) | ⚠️ 하락 |
| Scan API p95 | 154ms | ⚠️ 증가 (400VU: 207ms) |
| 완료 시간 p95 | 76.3초 | ❌ 임계치(60초) 초과 |
| E2E p95 | 76.4초 | ❌ 증가 (400VU: 62초) |
| Throughput | 438 req/m | ✅ 최고치 |
| Polling 요청 | 46,335건 | 약 28회/job |
KEDA Scaling
| 시간 | 컴포넌트 | 스케일링 | 트리거 |
|---|---|---|---|
| 테스트 시작 | scan-worker | 1→3 | scan.vision 10 msg+, scan.answer 10msg+, scan.rule 20msg+ |
| +1분 | scan-api | 1→2 | CPU 사용률 |
| +2분 | scan-api | 2→3 | CPU 사용률 |
| 테스트 종료 | scan-worker | 3→1 | 메트릭 정상화 |
Redis Streams 상태 (테스트 후)
scan:events:0: 4,970
scan:events:1: 4,440
scan:events:2: 4,970
scan:events:3: 5,460
총: 19,840개 (균등 분배 ±11%)
전체 부하 테스트 결과 비교 (50 ~ 500 VU)
| 50 | 685 | 99.7% | 198 req/m | 17.7초 | 93ms | ✅ 여유 |
| 200 | 1,649 | 99.8% | 367 req/m | 33.2초 | 83ms | ✅ 여유 |
| 250 | 1,754 | 99.9% | 417.6 req/m | 40.5초 | 78ms | ⭐ 서비스 최적점 |
| 300 | 1,732 | 99.9% | 402 req/m | 48.5초 | 83ms | ⚠️ 포화 시작 |
| 400 | 1,901 | 98.9% | 422.2 req/m | 62.2초 | 207ms | ⚠️ 한계 근접 |
| 500 | 1,990 | 94.0% | 438 req/m | 76.4초 | 154ms | ⚠️ 완료율 하락(-5%) |
한계 징후 도출
┌────────────────────────────────────────────────────────────────────────┐
│ 🎯 500 VU = 단일 노드 한계점 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ 📉 완료율 하락 │
│ • 400 VU: 98.9% → 500 VU: 94.0% (4.9%p 하락) │
│ • 처음으로 95% 이하로 떨어짐 │
│ │
│ ⏱️ 응답 시간 급증 │
│ • E2E p95: 62초 → 76초 (22.6% 증가) │
│ • SLA 임계치(60초) 크게 초과 │
│ │
│ 📊 Throughput은 증가 │
│ • 7.37 req/s (역대 최고치) │
│ • 하지만 완료율 5% 감소 │
│ │
└────────────────────────────────────────────────────────────────────────┘
VU 600 부하 테스트 시도


- OpenAI API quota 초과로 테스트 진행 불가
- quota 갱신 후 VU 600부터 이어서 진행할 예정
OpenAI API Usage

- 이코에코 서비스용 API 키, 테스트 신뢰성을 위해 실제 모델(GPT 5.1)을 유지하며 진행
- 소모 토큰: 1억 400만
현재 LLM API Usage Tier


- Tier 3으로 월 1,000$까지 호출 가능
- 아직 Usage Limits엔 도달하지 않았으나, 개인 비용 문제로 당일 부하 테스트는 500VU에서 중단