클라우드 과부하 - 100-hours-a-week/16-Hot6-wiki GitHub Wiki
특가 출시 기준 부하 테스트 시나리오
1. 목적
- Spring Boot 앱을 Docker 컨테이너에 배포할 때, 실제 예상 부하를 기준으로 --cpus, --memory 값을 최적화합니다.
- 자원 낭비는 줄이고, 서비스 장애 없이 동시접속을 견디도록 구성합니다.
- 이후 Blue-Green 배포 및 GitHub Actions CD 파이프라인과 통합 가능하게 합니다.
⠀
2. 대상 앱 정보
- 프레임워크: Spring Boot
- 실행 환경: Docker container
- 엔드포인트 예시:
- GET backend.onthe-top.com/api/~
- POST backend.onthe-top.com/api/~
⠀
3. 테스트 시나리오 구성 (특가 이벤트 기준)
시나리오 가정
- 오전 10시 특가 이벤트 오픈
- 동시접속자: 최대 1,000명
- 사용자당 평균 3~5 API 요청
- 트래픽은 오픈 직후 3분간 집중됨
⠀요청량 예측 (RPS 기준) ——> 향후 측정하고 싶은 엔드포인트에 맞게 변경.
API | RPS | 비고 |
---|---|---|
GET backend.onthe-top.com/api/~ | 1000 | |
GET backend.onthe-top.com/api/~{id} | 600 | |
POST backend.onthe-top.com/api/~/ | 300 |
4. 무제한 컨테이너로 먼저 실행
docker run -d --name springapp-unlimited -p 8080:8080 springapp:latest
- Docker에 리소스 제한 없이 먼저 실행합니다.
⠀
5-1 부하테스트 도구 선택
wrk vs k6 비교 요약
항목 | wrk | k6 |
---|---|---|
언어 기반 | C (고성능) | JavaScript (테스트 시나리오 스크립트 기반) |
특징 | - 초당 수천~수만 RPS 가능- 매우 빠름 | - 복잡한 시나리오 구성 가능- 사용자 흐름 표현 |
사용 목적 | 단순하고 빠른 부하 테스트 (GET/POST 반복 등) | 실제 사용자 행동 기반 시나리오 시뮬레이션 |
사용 방식 | 커맨드라인에서 직접 실행 | JavaScript 스크립트 작성 후 실행 |
UI / 대시보드 | 없음 (CLI 출력만) | 기본 CLI + Grafana 연동 가능 |
Docker 적합성 | 아주 좋음 (경량, CLI 기반) | 좋음 (컨테이너화 가능 + CI/CD 통합 유리) |
학습 난이도 | 매우 쉬움 | 약간 학습 필요 (JS 문법, 구조 이해) |
라이선스 | 오픈소스 (MIT) | 오픈소스 (AGPLv3), Cloud 버전은 유료 옵션 있음 |
사용 상황 정리
상황 | 추천 도구 |
---|---|
초당 수천 건 이상의 GET 요청 테스트 | wrk |
"로그인 → 상품 조회 → 구매" 시나리오 테스트 | k6 |
CI/CD 파이프라인에 부하 테스트 포함시키기 | k6 |
리소스 소모 적은 빠른 부하 확인 | wrk |
사용 예시
wrk
wrk -t12 -c1000 -d30s backend.onthe-top.com:8080/api/~
- 12개 스레드, 1000개 연결로 30초간 테스트합니다.
k6
# script.js
import http from 'k6/http';
export default function () {
http.get('backend.onthe-top.com:8080/api');
}
k6 run --vus 500 --duration 1m script.js
- 500명의 가상 사용자가 1분간 시뮬레이션합니다.
⠀
결론
- 빠르고 단순한 테스트 → wrk
- 사용자 시나리오 기반 정밀 테스트 + CI/CD 통합 → k6
둘 다 사용하는 게 이상적이지만, wrk은 스펙 산정용이지만 k6은 사용자 시나리오 검증 및 자동화 기반용으로 사용하기 때문에 실제 유저 행동 흐름을 반영한 정밀 테스트 + 확장성 + 자동화에 유리함으로, 비중을 높게 가져가는게 좋다고 생각했습ㄴ디ㅏ. 비중은 k6 (70%) + wrk 보조(30%).
5-2. 부하 테스트 도구 실행
현재 구조에서 부하 테스트는 프론트가 아닌 "백엔드 내부 네트워크 또는 내부 서버"에서 직접 실행해야 합니다. 부하 테스트는 백엔드에 직접 요청을 많이 보내는 것이기 때문에, React/S3를 거치면 오히려 부하가 분산되고 테스트 목적과 맞지 않습니다. 게다가 S3 정적 사이트는 부하를 만들 수 없고, 브라우저는 대량 요청이 불가합니다.
올바른 테스트 위치 - (백엔드가 실행되는 서버 안)
Wrk 사용 (고성능 GET 요청)
wrk -t12 -c1000 -d180s backend.onthe-top.com:8080/api/~
k6 예시 시나리오 기반으로
// script.js
import http from 'k6/http';
import { sleep } from 'k6';
export let options = {
stages: [
{ duration: '30s', target: 500 },
{ duration: '30s', target: 1000 },
{ duration: '1m', target: 2000 },
{ duration: '1m', target: 500 },
],
};
export default function () {
http.get('http://localhost:8080/엔드포인트');
sleep(1);
}
k6 run script.js
6. 리소스 사용량 측정
docker stats springapp-unlimited
또는:
- htop 또는 top
- Prometheus + Grafana
- APM 도구 (Elastic APM)
⠀기록 예시:
자원 | 최대 사용량 |
---|---|
CPU | 1.9 vCPU |
메모리 | 1.6 GB |
평균 응답시간 | 250ms |
오류율 | 0.5% |
7. Docker 제한 스펙 계산
→ JVM이 GC로 메모리를 많이 쓰기 때문에 메모리는 여유 있게, CPU는 측정값 + 20% 정도
docker run -d --name springapp-limited \
--cpus="2" \
--memory="2g" \
-p 8081:8080 \
springapp:latest
- 포트 8081로 제한된 컨테이너 실행 (Blue-Green 구조 가능)
⠀
8. 다시 동일 시나리오로 테스트
http.get(“backend.onthe-top.com/api/엔드포인트”);
→ 성능이 여전히 양호한지 확인
지표 | 무제한 컨테이너 | 제한 컨테이너 | 비고 |
---|---|---|---|
평균 응답시간 | 250ms | 270ms | OK (소폭 증가) |
오류율 | 0.5% | 0.5% | OK |
CPU | 1.9 vCPU | 1.95 vCPU | OK |
메모리 | 1.6 GB | 1.9 GB | OK |
9. 스펙 확정 및 반영
- 확정된 스펙 → Dockerfile / docker-compose / Helm chart 등에 반영합니다.
- 예:
docker-compose.yml 일부
services:
app:
image: springapp:latest
deploy:
resources:
limits:
cpus: "2.0"
memory: "2g"
10. Blue-Green 배포 활용
- 기존 컨테이너(Blue: 8080) → 새 버전 컨테이너(Green: 8081)
- 동일 부하 시나리오로 성능을 비교합니다.
- 문제가 없으면 Green을 Live로 전환합니다.
Blue-Green 배포에서 포트 기반 컨테이너 전환 설명
- Blue: 현재 운영 중인 안정된 버전 (예: 포트 8080)
- Green: 새로 배포한 테스트용 버전 (예: 포트 8081)
- 두 버전을 동시에 실행하고,
- 트래픽만 전환하여 배포/롤백을 빠르게 수행
동작 방식
- 테스트 완료 후 문제가 없으면:
- 트래픽을 8081로 전환 → Green이 운영 버전이 됨
- 문제가 생기면:
- 8081 컨테이너만 종료 → Blue 그대로 유지
목적
- 무중단 배포 가능
- 실시간 버전 비교 / 테스트
- 즉시 롤백 가능 (컨테이너만 내리면 끝)
실제 Docker 명령어 예시
# 운영 버전 (Blue)
docker run -d --name springapp-v1 -p 8080:8080 springapp:1.0
# 새 버전 (Green)
docker run -d --name springapp-v2 -p 8081:8080 springapp:2.0
트래픽 전환 방법
- 수동 전환:
- Nginx 설정에서 proxy_pass 대상 포트만 8080 → 8081로 변경
- 자동화 전환:
- Load Balancer나 GitHub Actions, ArgoCD 등을 통해 자동 스위치
11-1. APM 도구 도입 이유
APM이 필요한 이유
“특가 출시 상황”을 가정해 부하 테스트 중 /api의 엔드포인트에 수백~수천 RPS가 요청됩니다. Docker 리소스 스펙을 정하기 위해 병목 지점, 과부하 구간 분석이 필요합니다.
일반 부하 테스트 도구 | APM 도구 |
---|---|
응답시간, 실패율, CPU/Mem만 보여줌 | 왜 느려졌는지, 어디서 느려졌는지까지 보여줌 |
wrk와 apm 비교
wrk 결과:
- /purchase 응답시간이 600ms → 1200ms로 증가함
- CPU는 70%, 메모리는 여유 있음
⠀왜 느려졌는지 wrk만으론 알 수 없습니다.
APM을 보면:
- /purchase 트랜잭션에서:
- DB insert에 800ms 소요됨
- Redis Cache miss 발생
- 특정 메서드에서 N+1 쿼리 발생
- GC가 빈번하게 발생함
⠀병목 원인을 코드/쿼리/GC 레벨에서 정확히 확인할 수 있습니다.
목적 | 설명 |
---|---|
병목 위치 파악 | 컨트롤러? 서비스? 쿼리? GC? 어디에서 지연이 생기는지 확인 |
부하 분산 설계 기반 확보 | 특정 API나 쿼리에 집중되는 트래픽 분석 가능 |
Docker 스펙 최적화 보조 | CPU 사용이 높은 이유 → GC 때문인지? 코어 부족인지? |
장애 시 빠른 원인 추적 | 응답 지연, 500 오류 발생 시 빠르게 구간 파악 |
Blue/Green 비교 | v1 vs v2 트랜잭션 구조 차이 시각화 가능 |
11-2. APM 도구 선정.
APM 도구 목록
도구 | 유형 | Spring Boot 지원 | Docker 친화성 | SaaS 여부 |
---|---|---|---|---|
Elastic APM | 오픈소스 | 강력 (공식 지원) | 매우 좋음 | 자체 운영 |
Datadog APM | SaaS | 자동 계측 가능 | 좋음 | 구독형 |
New Relic | SaaS | 좋음 | 좋음 | 구독형 |
Sentry (Perf) | SaaS/오픈소스 | 성능 계측 한정 | 가볍게 가능 | (프리 티어 있음) |
세부 비교
항목 | Elastic APM | Datadog APM | New Relic | Sentry Performance |
---|---|---|---|---|
Spring Boot 연동 | 매우 쉬움 (apm-agent-attach) | 아주 쉬움 (에이전트 자동설정) | 쉬움 | 오류 추적은 뛰어남, 성능은 한정적 |
대시보드 | Kibana로 자유롭게 시각화 | 매우 직관적 (UI 우수) | 보기 편함 | 기본적인 퍼포먼스 UI |
분석 수준 | 트랜잭션/쿼리/GC까지 가능 | 전체 스택 추적, 로그/메트릭 통합 | 전체 분산 트레이스 | 경량 추적에 적합 |
Docker 연동 | 에이전트 + 호스트 내 서버 | Agent 컨테이너 있음 | 에이전트 설치 | SDK 기반 |
보안 격리 | 내부망 구축 가능 | SaaS 전송 (VPC 피어링 가능) | SaaS 전송 | SaaS 전송 |
비용 | 무료 (자체 운영시) | 유료 (프리 티어 제한적) | 유료 (가격 비슷) | 무료 플랜 있음 |
CD 통합 (GitHub Actions 등) | 가능 | 가능 (태깅/배포 추적 자동) | 가능 | 가능 (릴리즈 추적 위주) |
현재 조건에 가장 적합한 도구 : Elastic APM
선정 이유:
- Spring Boot + Docker 조합에서 가장 강력한 오픈소스 APM입니다.
- 자체 서버(Docker 또는 EC2)에 APM 서버 + Kibana 올려서 내부망만으로 구성이 가능합니다.
- GC, SQL 쿼리, HTTP 응답, Exception 모두 추적할 수 있습니다.
- 자체 구축임으로 비용이 없습니다.
- 이후 GitHub Actions 배포 시 릴리즈 추적이 가능합니다.
11-2. APM 도구 추가비교
상황 맞춤형 비교표
항목 | Scouter | Elastic APM |
---|---|---|
목적 | 빠른 성능 확인, 병목 추적 | 정교한 모니터링, 분석, 시각화 |
설치 난이도 | 매우 쉬움 (agent 붙이기만 하면 됨) | APM Server + Kibana 구성 필요 |
계측 범위 | JVM 전용 (메서드, SQL, GC 등) | JVM 포함, 다중 언어 + 쿼리 + 에러 추적 |
대시보드/시각화 | 기본 Web UI 제공 | Kibana 기반 고급 시각화 지원 |
Docker 친화성 | Docker로 구성 가능, 약간의 설정 필요 | Docker-Compose로 공식 구성 가능 |
내부망 설치 | 가능 (온프레미스 100%) | 가능 (Elastic Stack 자체 호스팅 시) |
커스터마이징 | 낮음 (정해진 UI) | 높음 (Kibana 시각화 자유로움) |
분석 깊이 | 가볍고 빠르지만 분석은 얕음 | 요청 트레이스, DB 쿼리, 에러 등 상세 분석 |
비용 | 무료 | 무료 (자체 운영시) |
상황 | 추천 APM | 이유 |
---|---|---|
빠르게 설치하고 성능 보기, JVM 앱만 있음 | Scouter | 가볍고 쉽고 빠름. 부하 테스트에 적합 |
장기적으로 운영/분석/확장까지 고려 | Elastic APM | 시각화, 대시보드, SQL/GC/분산 추적까지 가능 |
단기 성능 확인 / 테스트 위주면 Scouter 운영 환경 전반 / CI-CD 통합 / 시각화 기반 분석까지 고려하면 Elastic APM
Scouter가 더 적합한 경우
당장 Docker 환경에서 부하 테스트 결과를 빠르게 확인하고, 팀에서 JVM(Spring Boot) 앱만 운영하고, ELK 구성 없이도 APM 기능이 필요한 경우에 적합합니다.
Elastic APM이 더 적합한 경우
운영 환경까지 포함해서 정식 도입할 APM을 고민 중이고, Prometheus, Grafana, Kibana 같은 시각화/분석 통합을 고려하고 있고, SQL 쿼리/GC/에러/배포 추적까지 한 화면에서 보고 싶고, 향후 Python, Node.js, 또는 프론트엔드까지도 같이 계측하고 싶은 경우에 더 적합합니다.
최종 판단
목적 | 추천 |
---|---|
부하 테스트와 성능 확인 (단기) | Scouter |
운영 환경 통합/지속 분석 (장기) | Elastic APM |
Elastic APM만 써도 사실 충분하긴 하만 Scouter부터 빠르게 써보고, 나중에 Elastic APM으로 확장하는 전략도 좋다고 생각합니다.