글에 들어가기에 앞서..
이 글은 E - Commerce 도메인의 API별 테스트 목적에 따라 부하테스트를 진행하고 결과를 분석하여 개선할 점을
찾아보는 과정을 정리한 글입니다. 또한, 해당 테스트를 통해 예상할 수 있는 장애에 대한 대응책도 정리해볼 생각입니다.
각 API별 테스트 실행 및 결과 분석
1. 상품 목록 조회
✅ 테스트 목적
상품 목록 조회 API는 사용자가 가장 많이 호출하는 핵심 API 중 하나입니다. 트래픽이 몰리는 경우에도 안정적으로
응답해야 하며, 검색 필터나 정렬 옵션이 추가될 경우 성능 저하가 발생할 수 있습니다. 따라서, 일정 수준 이상의
부하에서도 응답 시간이 몇초 정도 이하로 유지되는지 확인하고, 데이터베이스 부하가 증가할 때 장애 없이 견딜 수 있는지
검증해볼 생각입니다.
✅ 테스트 시나리오 요약
| 테스트 유형 | 동시 사용자 | 지속 시간 |
| 기본 테스트 | 500명 | 3분 |
| 부하 테스트 | 500명(0명에서부터 점진적으로 증가) | 3분 |
| 스트레스 테스트 | 1000명 | 3분 |
✅ K6 테스트 스크립트
[기본 성능 테스트]
import http from 'k6/http';
import { check, sleep } from 'k6';
export let options = {
vus: 500, // 500명의 동시 사용자
duration: '1m' // 1분 동안 실행
};
export default function () {
let res = http.get('http://localhost:8080/products?page=0&size=10');
check(res, {
'is status 200': (r) => r.status === 200,
});
sleep(1);
}
[부하 테스트]
import http from 'k6/http';
import { check, sleep } from 'k6';
export let options = {
stages: [
{ duration: '1m', target: 100 }, // 1분 동안 100명까지 증가
{ duration: '1m', target: 300 }, // 1분 동안 300명까지 증가
{ duration: '1m', target: 500 }, // 1분 동안 500명까지 증가 후 유지
],
};
export default function () {
let res = http.get('http://localhost:8080/products?page=0&size=10');
check(res, {
'is status 200': (r) => r.status === 200,
});
sleep(1);
}
[스트레스 테스트]
import http from 'k6/http';
import { check, sleep } from 'k6';
export let options = {
vus: 1000, // 동시 사용자 1,000명
duration: '3m' // 3분 동안 유지
};
export default function () {
let res = http.get('http://localhost:8080/products?page=0&size=10');
check(res, {
'is status 200': (r) => r.status === 200,
});
sleep(1); // 각 사용자가 1초마다 요청
}
✅ 테스트 결과
| 테스트 유형 | 응답 시간 | TPS | 오류율 (%) | 동시 사용자 |
| 기본 테스트 | 1.15s | 231.5 | 0.00% | 500 |
| 부하 테스트 | 1.19s | 139.3 | 0.00% | 0 ~ 500 |
| 스트레스 테스트 | 6.34s | 183.2 | 0.23% | 10000 |
✅ 결과 분석
이번 부하 테스트 결과, 상품 목록 조회 API(GET /products)는 높은 동시 사용자 환경에서도 안정적으로 요청을 처리할 수 있음을 확인했습니다.
기본 테스트 결과, 동시 500명의 사용자가 API를 호출하는 환경에서도 오류율 0%를 유지했으며, 초당 평균 231.5개의 요청(TPS)을 처리할 수 있었다. 평균 응답 시간은 1.14초였지만, 모든 요청이 정상적으로 응답되었고, 시스템이 안정적으로 동작함을 확인할 수 있었습니다!
부하 테스트에서도 동시 500명의 사용자 요청을 점진적으로 증가시키는 방식으로 진행한 결과, API는 오류 없이 요청을 정상적으로 처리했으며, TPS는 139.3으로 일정 수준을 유지했으며. 응답 시간이 평균적으로 554.03ms로 측정되었으며, p95 기준 1.19초로 다소 증가했지만, 안정적인 범위 내에서 유지됨을 확인했습니다.
스트레스 테스트의 경우, 10000명의 동시 사용자가 API를 호출하는 극한 상황에서도 99% 이상의 요청을 정상적으로 처리했으며, TPS는 183.2까지 증가했다. 일부 요청에서 응답 시간이 증가했으나, 오류율은 0.23%로 매우 낮은 수준을 유지하여, 높은 부하 환경에서도 API가 비교적 안정적으로 동작했습니다. 다만, 대용량 트래픽에서의 응답시간은 최적화 방법을 생각해 보고 개선해 봐야 할 사항인 것 같습니다!
2. 선착순 쿠폰 발급
✅ 테스트 목적
선착순 쿠폰 발급 API는 트래픽이 집중될 가능성이 높은 기능 중 하나로, 이벤트나 프로모션 시 대량의 사용자가 동시에 요청할 가능성이 높다고 생각 했습니다. 따라서, 쿠폰 발급 요청이 동시에 발생할 경우에도 시스템이 안정적으로 처리할 수 있는지 부하테스트를 통해 검증하기로 선택했습니다..
특히, 동시에 많은 요청이 들어오면 쿠폰 발급 로직이 올바르게 동작하는지, 중복 발급 방지 기능이 정상적으로 처리되는지 확인해보며, Redis의 로직이 잘 동작하는 지를 확인 해봤습니다!
✅ 테스트 시나리오 요약
| 테스트 유형 | 동시 사용자 | 지속 시간 |
| 기본 테스트 | 100명 | 2분 |
| 부하 테스트 | 500명(0명에서 점진적으로 증가) | 3분 |
| 스트레스 테스트 | 10000명 | 3분 |
✅ K6 테스트 스크립트
[기본 테스트]
export default function () {
let couponId = 1;
let url = `http://localhost:8080/coupons/${couponId}`;
let payload = JSON.stringify({
userId: 1
});
let params = {
headers: {
'Content-Type': 'application/json'
}
};
let res = http.post(url, payload, params);
check(res, {
'is status 200': (r) => r.status === 200,
});
sleep(1);
}
[부하 테스트]
import http from 'k6/http';
import { check, sleep } from 'k6';
export let options = {
stages: [
{ duration: '1m', target: 100 }, // 1분 동안 100명까지 증가
{ duration: '1m', target: 300 }, // 1분 동안 300명까지 증가
{ duration: '1m', target: 500 }, // 1분 동안 500명까지 증가 후 유지
],
};
export default function () {
let couponId = 1;
let url = `http://localhost:8080/coupons/${couponId}`;
let payload = JSON.stringify({
userId: 1
});
let params = {
headers: {
'Content-Type': 'application/json'
}
};
let res = http.post(url, payload, params);
check(res, {
'is status 200': (r) => r.status === 200,
});
sleep(1);
}
[스트레스 테스트]
import http from 'k6/http';
import { check, sleep } from 'k6';
export let options = {
vus: 10000, // 동시 사용자 10000명
duration: '3m' // 3분 동안 유지
};
export default function () {
let couponId = 1;
let url = `http://localhost:8080/coupons/${couponId}`;
let payload = JSON.stringify({
userId: 1
});
let params = {
headers: {
'Content-Type': 'application/json'
}
};
let res = http.post(url, payload, params);
check(res, {
'is status 200': (r) => r.status === 200,
});
sleep(1);
}
✅ 테스트 결과
| 테스트 유형 | 응답 시간(p95) | TPS | 오류율(%) | 동시 사용자 |
| 기본 테스트 | 800ms | 200 | 0.00% | 100 |
| 부하 테스트 | 1.4s | 450 | 0.2% | 0 ~ 500 |
| 스트레스 테스트 | 3.2s | 700 | 1.8% | 10000 |
✅ 결과 분석
이번 부하 테스트 결과, 선착순 쿠폰 발급 API는 높은 동시 요청 환경에서도 정상적으로 요청을 처리한 것을
확인했습니다.
기본 테스트에서는 100명의 동시 사용자가 요청을 보냈을 때 응답 시간(p95) 800ms, 오류율 0%로 매우 안정적인 성능을 유지했다. TPS는 200으로, 사용자가 동시에 요청하더라도 API가 빠르게 처리하는 것을 확인할 수 있었습니다!
부하 테스트에서도 동시 500명의 사용자 요청이 점진적으로 증가하는 상황에서도 API는 오류 없이 요청을 정상적으로 처리했으며, TPS는 450으로 안정적으로 유지되었으며 응답 시간이 p95 기준 1.4초까지 증가했지만, 여전히 비교적 양호한 수준으로 응답하는 것을 확인할 수 있었습니다!
스트레스 테스트의 경우, 동시 10000명의 사용자가 쿠폰을 발급받기 위해 요청하는 극한 상황에서도 99% 이상의 요청을 정상적으로 처리했으며, TPS는 700까지 증가했다. 하지만 일부 요청에서 응답 시간이 3.2초까지 증가했고, 오류율이 1.8%로 증가하는 결과가 나타났습니다. 이 부분에 대해서는 DB 커넥션 부하를 개선해봐야 할 사항인 것 같습니다.
(가상) 장애 대응 전략
1. 장애 감지 (Monitoring & Alerting)
장애가 발생하기 전에 감지하고 대응할 수 있도록 실시간 모니터링 및 알람 시스템을 구축하는 것을 말합니다.
| 모니터링 대상 | 설명 | 도구 |
| 서버 리소스 | CPU, 메모리 사용량, 디스크 I/O | Prometheus, Grafana |
| 애플리케이션 성능 | API 응답 시간, 요청 수 | K6, Prometheus |
| DB 상태 | 커넥션 풀 사용률, Slow Query | MySQL Slow Query Log, Grafana |
| 에러 로그 | HTTP 5xx, DB Deadlock | Loki, ELK Stack |
| 트래픽 급증 감지 | 초당 요청 수 증가 감지 | Prometheus AlertManager |
2. 장애 원인 파악 및 대응 방법 정리

3. 장애 대응 프로세스
- 장애 감지 → Grafana, Prometheus 알림 설정
- 장애 원인 분석 → Slow Query, 로그 분석 (Loki, ELK Stack)
- 빠른 복구 → Auto Scaling, Circuit Breaker 등을 적용
- 사후 분석 및 개선 → 장애 리포트 작성, 재현 테스트 실행