서비스의 Capacity를 물으면 흔히:
EC2 CPU가 몇 Core인가?
RAM이 몇 GB인가?
부터 생각한다.
하지만 실제 처리 한계는:
API
DB
Connection Pool
Queue
Worker
Redis
외부 Provider
Network
File I/O
중 가장 먼저 포화되는 지점에서 결정된다.
예:
NestJS
1,000 req/s 가능
PostgreSQL
300 req/s 가능
이라면 실제 서비스 Capacity는 1,000이 아니다.
DB가 먼저 포화되므로 실질적으로는:
약 300 req/s 이하
에서 한계가 나타날 수 있다.
간단히 말하면:
앞으로 들어올 부하를 현재 시스템이 얼마나 처리할 수 있는지 측정하고, 언제 어떤 자원을 확장해야 하는지 미리 판단하는 것
이다.
최소한 다음을 답할 수 있어야 한다.
현재 평소 Traffic은?
Peak Traffic은?
현재 처리 한계는?
병목은 어디인가?
여유 Capacity는 얼마나 남았는가?
2배 Traffic이 와도 버티는가?
확장 시 무엇을 먼저 늘려야 하는가?
측정 없이:
서버 충분한 것 같은데?
또는:
RDS부터 키워야 할 것 같은데?
라고 판단하면 안 된다.
예:
API RPS
p50 / p95 / p99 Latency
HTTP Error Rate
CPU
Memory
DB Query Latency
DB Connections
Queue Depth
Worker Throughput
Redis Memory
정도다.
예:
평균 응답시간
100ms
라고 해도:
p95
1.2초
p99
4초
일 수 있다.
사용자 일부는 이미 매우 느린 경험을 하고 있다는 뜻이다.
일 평균:
10 RPS
여도 광고 캠페인이나 사전예약 오픈 때:
200 RPS
까지 올라갈 수 있다.
Capacity는 평균보다 Peak 상황이 중요하다.
예:
일반 상품 조회
검색
주문 접수
관리자 조회
알림 Job
Export
AI 분석
은 모두 Resource 사용 특성이 다르다.
예:
상품 목록
상품 상세
FAQ
검색
주문 접수
상태 변경
Audit
Webhook 저장
이다.
Scaling 전략도 달라진다.
예:
GET /products/123
DB PK Query 1회
와:
GET /admin/orders
복잡한 Filter
Join
Count
Sort
Pagination
은 같은 Request 1개가 아니다.
예:
100 RPS
라도 모두 상품 조회인 경우와:
100 RPS
모두 복잡한 관리자 검색인 경우는 전혀 다르다.
예:
Product Detail
CPU 낮음
DB 낮음
Cache 가능
Admin Order Search
CPU 중간
DB 높음
Export
Memory 높음
DB 높음
File I/O 높음
AI Run
CPU/GPU/Memory 높음
Long-running
처럼 분류한다.
시스템 처리량을 제한하는 가장 좁은 부분이다.
예:
CPU 30%
Memory 40%
DB Connection Pool 100%
이면 CPU를 늘려도 별 도움이 없을 수 있다.
나쁜 대응:
서비스 느림
↓
EC2 사양 2배
이다.
실제 원인이:
Missing Index
라면 비용만 늘고 문제는 거의 그대로다.
대표적으로:
Application CPU
Application Memory
Event Loop
DB CPU
DB I/O
DB Lock
Connection Pool
Redis
Queue Worker
External API
Network
File I/O
가 있다.
증상 예:
CPU 90~100%
Latency 상승
DB는 여유
Event Loop 지연
이다.
예:
대량 JSON 변환
이미지 처리
암호화
큰 Excel 생성
복잡 계산
AI 로컬 실행
등이다.
NestJS의 주 Event Loop에서 큰 CPU 작업을 실행하면 다른 요청도 같이 느려진다.
예:
Excel 생성
대형 Report
AI 분석
등은 Background Worker로 넘긴다.
증상:
Memory 지속 증가
GC 빈번
Swap
Process OOM
등이다.
Spike:
대형 Export 실행
→ Memory 일시 증가
→ 작업 종료 후 감소
Leak:
요청이 계속될수록
Memory가 계속 증가
이다.
예:
100만 Row를
Memory에 전부 로드
↓
Excel 생성
은 위험하다.
가능하면:
DB Cursor
↓
10,000 Row
↓
File Write
↓
다음 10,000 Row
처럼 처리한다.
증상:
RDS CPU 높음
Query Latency 증가
Application CPU 낮음
이다.
순서:
Slow Query 확인
EXPLAIN
Index
N+1
Pagination
Select Column
Join
이다.
Query가 잘못됐는데 DB 사양만 늘리면 문제를 늦출 뿐이다.
예:
Pool Size
20
Active
20
Waiting
80
이면 새 Request가 Connection을 기다린다.
Application Instance마다:
20 connections
을 갖고 있고 서버를 10대로 늘리면:
200 connections
이 DB로 몰린다.
이게 중요한 함정이다.
App 2대 → 10대
로 늘렸는데 DB가 그대로면 전체 Connection 수와 Query량이 증가한다.
예:
DB max connections
200
Reserved
40
Application Budget
160
이라고 하자.
App 4대면:
40 per instance
보다 낮게 설정해야 한다.
Admin Tool, Migration, Monitoring 연결도 필요하기 때문이다.
App Scale 정책과 같이 봐야 한다.
CPU는 낮은데 Query가 느릴 수 있다.
원인:
Long Transaction
동시 Update
Lock Wait
이다.
Transaction 구조를 고쳐야 한다.
예:
Order Detail
p95 15ms
Admin Search
p95 700ms
Report
p95 8s
라면 Report/Search가 병목 후보다.
예:
Cache
Queue
Rate Limiter
를 같은 Redis가 담당하면 한 Resource에 의존성이 몰릴 수 있다.
Cache Eviction뿐 아니라 Queue 안정성에 영향이 갈 수 있다.
1004와 연결된다.
Producer:
500 jobs/min
Consumer:
200 jobs/min
이면 매분:
300 jobs
가 쌓인다.
대략:
처리 완료 Job 수
/
시간
으로 본다.
Worker가 초당 많이 처리해도 특정 Job이 너무 오래 기다릴 수 있다.
그래서:
Throughput
Queue Depth
Oldest Age
Job Duration
을 같이 본다.
우리 서버는 여유가 있어도:
Kakao
Notion
LLM API
외부 Provider
가 느리면 전체 Workflow가 느려진다.
그래서:
Rate Limit
Queue
Concurrency
Circuit Breaker
로 보호한다.
실제 또는 가상의 Traffic을 발생시켜:
시스템이 어느 수준부터 느려지고 실패하는지 측정하는 테스트
다.
좋은 질문:
언제 p95가 급증하는가?
어느 Resource가 먼저 포화되는가?
Error가 어디서 시작되는가?
Queue는 얼마나 밀리는가?
이다.
Load Test:
예상 Traffic 범위에서
성능 확인
Stress Test:
한계까지 밀어붙여
어디서 무너지는지 확인
이다.
갑작스러운 Traffic 증가를 본다.
예:
10 RPS
↓
1초 만에
200 RPS
이다.
사전예약/광고 오픈 상황에 유용하다.
장시간 일정 부하를 유지한다.
예:
50 RPS
8시간
이다.
Memory Leak이나 Connection Leak을 찾기 좋다.
Baseline Test
Load Test
Stress Test
Spike Test
Soak Test
를 목적에 따라 사용한다.
현재는:
Baseline
예상 Peak
Peak × 2
정도부터 시작하면 충분하다.
실제 고객과 DB를 위험하게 만들 수 있다.
가능하면:
유사 Schema
더미 데이터
유사 Application Config
로 구성한다.
예:
Staging
1 vCPU
Production
4 vCPU
이면 Test 결과를 직접 비교하기 어렵다.
예:
Index 적용 전
p95 1.5s
Index 적용 후
p95 300ms
같은 개선 비교에는 유용하다.
실제 서비스 영향이 없는:
Read-only Endpoint
저트래픽 시간
Controlled Ramp
에서만 신중하게 수행한다.
예:
Error Rate > 5%
→ 중단
DB CPU > 85%
→ 중단
p95 > 3s
→ 중단
같은 Stop Condition을 둔다.
갑자기:
0 → 1,000 RPS
하지 않는다.
예:
10 RPS
2분
25 RPS
2분
50 RPS
2분
100 RPS
2분
이다.
Metric이 반응하는 시간을 본다.
예:
50%
상품 목록
30%
상품 상세
10%
검색
5%
주문
5%
기타
처럼 실제 Traffic과 비슷하게 구성한다.
먼저 Access Log/Analytics를 본다.
고객 Traffic과:
관리자 주문 검색
Excel Export
상태 변경
을 같은 Load Pattern으로 보지 않는다.
예:
GET /products
GET /products/:id
GET /faq
부터 시작한다.
다양한 Query로 테스트한다.
같은 Query만 반복하면 Cache 효과 때문에 실제보다 좋아 보일 수 있다.
Cache가 채워진 상태
Cache가 비어 있는 상태
둘 다 확인한다.
Redis 재시작이나 Cache Version 변경 후 실제로 발생할 수 있다.
주문 생성은 실제 Side Effect가 있으므로 Test 전용 데이터/환경에서만 한다.
동일 Request를 여러 번 보내:
중복 주문이 안 생기는가?
확인한다.
다양한 조합:
상태 Filter
날짜 Filter
검색
정렬
Pagination
을 테스트한다.
예:
기간 넓음
검색어 있음
정렬 있음
처럼 비용이 큰 조합이다.
HTTP Response 시간만 보면 안 된다.
Export Request 생성
Queue 대기
Worker 처리
파일 생성
완료
전체 Workflow를 본다.
예:
jobs/hour
average duration
p95 duration
memory peak
queue age
이다.
예:
Provider allowed rate
Worker concurrency
Retry rate
Queue depth
를 본다.
예:
1 Run 평균 8분
동시 Run 1
이면 시간당 대략:
7~8건 이하
수준일 수 있다.
정확한 수치는 실제 측정해야 한다.
예:
runs/hour
이다.
예:
Web API
requests/sec
Notification
messages/sec
Export
jobs/hour
AI
runs/hour
이다.
부하를 올릴수록 보통:
낮은 부하
Latency 안정
↓
중간 부하
Latency 조금 증가
↓
포화 근처
Latency 급증
↓
한계 초과
Error 급증
형태가 된다.
Latency가 갑자기 크게 올라가기 시작하는 지점을 찾는다.
예:
200 RPS
포화 시작
운영 상한
140~160 RPS
처럼 여유를 둔다.
현재 사용량 대비 남겨둔 Capacity다.
예:
Peak CPU
50%
Available Headroom
약 50%
처럼 단순하게 볼 수 있다.
DB가 이미 80%라면 전체 Headroom은 작을 수 있다.
예:
Application CPU
60% 여유
DB CPU
20% 여유
DB Connections
10% 여유
Queue Throughput
40% 여유
이다.
업무 특성에 따라 다르다.
사전예약처럼 Spike가 예상되면 더 많은 여유가 필요할 수 있다.
예:
현재:
Peak Orders
500/day
월 증가:
10%
라면 몇 개월 후 예상 Peak를 대략 계산할 수 있다.
목표는:
언제쯤 확장이 필요할 가능성이 있는가?
를 미리 보는 것이다.
예:
신제품 출시
광고 캠페인
사전예약 오픈
은 과거 평균으로 예측하기 어렵다.
사전예약 시작 전:
평소 Traffic × 예상 배수
를 기준으로 별도 Test를 수행한다.
과거 캠페인, 광고 클릭량 등 근거를 사용한다.
한 서버를 더 크게 만드는 방식이다.
예:
2 vCPU / 4GB
↓
4 vCPU / 8GB
이다.
구현 단순
Architecture 변경 적음
운영 쉬움
이다.
트래픽이 아주 크지 않고 단일 서버 구조라면 먼저 사양을 올리는 것이 더 싸고 단순할 수 있다.
문제가:
Query Bug
Lock
External API
라면 서버 사양을 올려도 해결되지 않는다.
서버 Instance 수를 늘리는 방식이다.
1대
↓
2대
↓
4대
이다.
Capacity 증가
Instance 장애 격리
Rolling Deployment
가 쉬워진다.
State 관리가 복잡해진다.
예:
Local Cache
Local Session
Scheduler 중복 실행
Worker 중복 처리
문제가 생긴다.
Session 외부화
Shared Cache 필요 여부
Scheduler Lock
Worker Idempotency
Shared File Storage
를 본다.
API Instance가:
Local Disk
Local Session
Local State
에 의존하지 않을수록 좋다.
Instance A에서 업로드한 파일을 Instance B가 못 볼 수 있다.
S3 같은 공유 Storage가 더 적합하다.
서버 Memory에 Session이 있으면:
Request 1
Server A
Request 2
Server B
에서 문제가 생길 수 있다.
하지만 Revocation/Session State가 있다면 별도 고려한다.
Instance가 3대면 Cron도 3번 실행될 수 있다.
하나만 실행해야 하는 Scheduler는:
DB Lock
Redis Lock
Lease
등으로 중복을 막는다.
Queue에서 각 Worker가 Job을 가져가면 된다.
단:
Atomic Claim
Idempotency
Concurrency
가 필요하다.
예:
Notification Worker
1대 → 3대
로 처리량을 늘릴 수 있다.
Worker 3대가 각자 초당 20건을 보내:
60 req/s
가 되면 Provider Limit을 넘을 수 있다.
여러 Worker가 하나의 공유 Rate Limit을 사용한다.
대표적으로:
Scale Up
Read Replica
Partition
Sharding
등이 있다.
현재 규모에서 대부분:
Query Optimization
Index
RDS Scale-up
이 먼저다.
Read-heavy 서비스에서 조회 일부를 Replica로 보낼 수 있다.
Primary:
Order COMPLETED
직후 Replica에서는 아직:
WAITING
일 수 있다.
예:
상태 변경 직후 상세 조회
같은 경우다.
몇 초 지연이 괜찮다면 가능하다.
Read Load가 실제 병목일 때 도입한다.
Cache:
반복 Read 감소
Read Replica:
Read Query를 다른 DB에 분산
이다.
역할이 다르다.
상품/FAQ처럼 Stale 허용 가능한 데이터는 Cache가 먼저다.
하지만 현재 트래픽 규모에서 필요한지 측정한다.
예:
Query 최적화 완료
Connection 관리 정상
CPU/I/O 지속 포화
Traffic 증가 추세
일 때다.
예:
CPU 지속 80%+
Memory 지속 부족
Event Loop Lag
DB는 여유
등이다.
예:
한 Instance 한계 접근
무중단 배포 필요
Availability 요구 증가
Traffic 변동성 큼
등이다.
Queue Age 증가
Job Throughput 부족
Downstream은 여유
이다.
예:
Provider 20 req/s 제한
이면 Worker 20대가 의미 없다.
간단히:
Latency 상승
↓
App CPU 높음?
→ App 최적화 / Scale
아니오
↓
DB Latency 높음?
→ Query / DB 확인
아니오
↓
Queue Age 높음?
→ Worker 확인
아니오
↓
External API 느림?
→ Provider / Circuit / Rate Limit
처럼 본다.
EC2 2배
RDS 2배
Redis 2배
Worker 3배
를 한꺼번에 하면 어떤 변경이 효과가 있었는지 알 수 없다.
Measure
↓
Change
↓
Measure Again
한다.
50 RPS
p95 120ms
DB CPU 25%
100 RPS
p95 190ms
DB CPU 45%
150 RPS
p95 350ms
DB CPU 72%
180 RPS
p95 1.2s
DB CPU 95%
이라면 DB가 병목 후보다.
먼저 Slow Query/Index를 본다.
예:
Index 추가 후
180 RPS
p95 280ms
DB CPU 60%
가 됐다면 Infrastructure Scale 없이 Capacity가 늘어난 것이다.
좋은 Query 하나가 EC2/RDS 업그레이드보다 효과가 클 수 있다.
Scale은 비용을 만든다.
따라서:
성능
안정성
비용
세 가지를 같이 본다.
개념적으로:
월 Infra 비용
/
월 처리 요청 수
를 볼 수 있다.
AI/Export는 일반 GET보다 훨씬 비싸다.
그래서 업무별 Cost를 따로 볼 수 있다.
예:
Export 1건
AI Report 1건
Notification 1건
당 대략 비용을 계산할 수 있다.
예:
LLM Token
문자/알림 비용
Storage
Data Transfer
등이다.
예:
중복 API 호출
N+1
불필요한 전체 Select
중복 AI Run
Cache 미사용
이다.
예:
Optimization 2주 필요
Server Upgrade 월 +3만원
이고 Traffic이 작은 경우라면 서버 업그레이드가 더 경제적일 수도 있다.
Traffic이 늘수록 Scale 비용도 계속 올라간다.
예:
Redis Cluster
Read Replica
Auto Scaling
Service Discovery
를 관리하는 시간도 비용이다.
운영 시간이 과도하게 들면 총비용은 오히려 커진다.
가능하면:
한 단계 높은 EC2/RDS
가:
복잡한 Distributed Architecture
보다 나을 수 있다.
단일 서버가 장애 나면 전체 서비스가 멈출 수 있다.
서버 한 대가 충분히 빠르다고:
고가용성
인 것은 아니다.
서버 2대라면 한 대 장애 시 다른 서버가 처리할 수 있다.
RDS Multi-AZ 같은 별도 Availability 전략이 있다.
각각 우선순위를 따로 판단한다.
예:
정상 Peak에서
CPU 70% 이하
DB Connections 70% 이하
Queue Lag SLO 만족
같은 내부 기준을 둘 수 있다.
70%가 절대 규칙은 아니다.
예:
CPU 80% 이상 10분
Memory 85% 이상
DB Connection 80%
Queue Lag SLO 초과
등을 설정한다.
지속 시간과 반복성을 본다.
Metric에 따라 자동으로 Instance 수를 조절할 수 있다.
CPU
Request Count
Queue Depth
등이다.
하지만 CPU와 Traffic 상관관계가 실제로 있어야 한다.
예:
Queue Depth ↑
→ Worker 증가
이다.
Worker를 늘렸는데 DB/Provider가 먼저 포화되면 안 된다.
예:
min 1
max 5
처럼 상한을 둔다.
잘못된 Retry Storm에 Auto Scaling이 반응해 서버를 계속 늘릴 수도 있다.
최대 Capacity를 정한다.
Traffic이 잠깐 줄었다고 바로 Instance를 줄이면 다시 늘어날 때 출렁인다.
예:
Scale Up 후
10분 동안 Scale Down 금지
같은 안정화 기간을 둔다.
1005/1006과 같은 원리다.
먼저:
Metric
Load Test
Manual Scaling 기준
을 잡는다.
예:
1. 병목 Metric 확인
2. 최근 Traffic 증가 확인
3. Query Regression 확인
4. Cache 상태 확인
5. Queue 상태 확인
6. Scale 필요 여부 결정
7. 한 단계 Scale
8. 재측정
이다.
어제까지 정상인데 오늘 갑자기 느려졌다면:
Traffic 성장
보다:
새 배포 Bug
일 가능성도 있다.
Metric Dashboard에 Release 시점을 표시하면 좋다.
09:00 release v123
09:05 DB latency 상승
같은 상관관계를 볼 수 있다.
신규 기능이:
Orders 조회마다
추가 Query 20개
를 만들었을 수 있다.
중요 API의 성능이 배포마다 악화되지 않는지 확인한다.
Admin Order List
p95 baseline 300ms
신규 변경
p95 900ms
이면 Review한다.
시간과 비용이 크다.
예:
대표 Query 100회
평균/p95 비교
정도로 Regression을 잡을 수 있다.
예:
큰 Release 전
사전예약 전
Infra 변경 전
에 수행한다.
특히 Traffic 이벤트가 있다면:
아이폰 사전예약
갤럭시 출시
대규모 광고
전 미리 Capacity Test를 할 수 있다.
Cache Warm?
DB Index 확인?
Rate Limit 확인?
Queue Worker 확인?
Provider Limit 확인?
Kill Switch 준비?
Monitoring 준비?
이다.
실제 과거 Access Log를 기반으로 유사 Traffic을 재현할 수 있다.
익명화하거나 Pattern만 추출한다.
대표 Endpoint 비율로 생성한다.
예:
k6
Artillery
JMeter
같은 도구를 사용할 수 있다.
현재 Node/JS 환경이라면 k6나 Artillery가 접근하기 쉬울 수 있다.
좋은 Tool을 써도:
GET /
만 1000번
이면 실제 Capacity를 제대로 알기 어렵다.
Orders 100건 DB와:
Orders 1,000,000건
DB의 Query 성능은 다르다.
적어도:
현재 Production 규모
앞으로 예상 규모
에 가까운 더미 데이터로 테스트한다.
가능하면 생성형 더미 데이터를 사용한다.
모든 Status가 동일한 더미 데이터면 실제 Query Planner 행동과 다를 수 있다.
예:
WAITING 10%
COMPLETED 70%
CANCELLED 20%
처럼 현실적인 분포를 재현한다.
동일 이름/번호 패턴만 넣지 않는다.
Debug Logging을 켜두면 Production보다 더 느릴 수 있다.
Staging 설정을 Production과 최대한 맞춘다.
정밀 Capacity 숫자가 필요하면 Network 경로도 유사하게 구성한다.
예:
Traffic
RPS
Peak RPS
Latency
p50/p95/p99
Application
CPU
Memory
Database
CPU
Connections
Query Latency
Queue
Depth
Oldest Age
Throughput
정도다.
주간으로:
Current Peak
Tested Capacity
Headroom
Top Bottleneck
Next Action
을 정리할 수 있다.
Peak
40 RPS
Tested Stable
150 RPS
Headroom
약 3.7x
Primary Bottleneck
Admin Search DB Query
같은 식이다.
“150 RPS까지 보장”이 아니라:
Staging Test 기준
150 RPS에서 SLO 만족
처럼 표현한다.
단순:
AWS 배포했습니다.
보다:
Load Test를 통해 DB 병목을 식별하고
Index 개선 후 p95와 처리량을 개선했다.
가 훨씬 강한 실무 경험이 된다.
예:
Before
Admin List p95 1.4s
After
420ms
처럼 근거를 남긴다.
예:
Dataset
500k rows
Concurrency
50
Environment
Staging
을 같이 남긴다.
예:
interface LoadTestRun {
id: string;
scenario: string;
environment: string;
startedAt: Date;
peakRps?: number;
p95?: number;
errorRate?: number;
bottleneck?: string;
}
정도로 기록할 수 있다.
Markdown Report로 저장해도 충분할 수 있다.
/docs/performance예:
/docs/performance/
2026-10-preorder-load-test.md
처럼 기록한다.
# 목적
# 환경
# Dataset
# Scenario
# Traffic
# Result
# Bottleneck
# Improvement
# Retest
# Capacity Recommendation
이다.
AI가 Metric/Load Test 결과를 받아:
Latency 증가 지점
DB CPU 상관관계
Queue 병목
Regression
을 요약할 수 있다.
입력:
RPS
50 → 100 → 150
p95
120 → 170 → 850
DB CPU
30 → 55 → 94
AI가:
150 RPS 부근에서 DB가 주요 병목 후보
라고 분석할 수 있다.
코드만 보고:
RDS를 Scale Up해야 합니다.
라고 결정하지 않는다.
적합:
Metric 요약
상관관계 후보
Slow Query 후보
Test Scenario 생성
Before/After Report
이다.
AWS Instance Type 변경은 비용과 Availability에 영향을 준다.
Human Approval이 적합하다.
예:
Recommendation
Query Optimization First
Reason
DB CPU rises with admin search traffic
Scale-up not yet required
처럼 근거를 남긴다.
| 상황 | 우선 대응 |
|---|---|
| App CPU 포화 | 코드 최적화 / App Scale |
| DB CPU 포화 | Query/Index → DB Scale |
| DB Connection 포화 | Pool/Query 확인 → Scale |
| Queue Lag 증가 | Worker/Downstream 확인 |
| External API 지연 | Rate Limit/Circuit/Queue |
| Memory Leak | Leak 수정 |
| Cache Miss Storm | Stampede 대응 |
Queue Age 증가
라고 바로 Worker를 늘리지 않는다.
평균 Job이 갑자기:
2초 → 20초
가 됐다면 외부 Provider가 느려진 것일 수 있다.
동시 요청이 더 늘어 Provider 장애를 악화시킬 수 있다.
1005의:
max concurrency
queue backlog
rate limit
은 Capacity를 실제 운영에서 지키는 장치다.
예:
Worker 안정 처리
20 concurrent
라면:
maxConcurrency = 20
등으로 제한한다.
실제 Guardrail에 반영한다.
예:
150 RPS까지 안정
Rate Limit
120 RPS
처럼 Safety Margin을 둔다.
무거운 Endpoint별 Limit도 필요하다.
예:
Interactive API
DB Connection 70%
Background Worker
30%
처럼 Resource를 나눌 수도 있다.
API/Worker별 Pool 또는 Concurrency를 제한할 수 있다.
0924의 Bulkhead가 실제 Capacity Allocation이 된다.
Notification
10 concurrency
Export
2
AI
1
으로 각각 Resource를 격리한다.
사전예약 오픈처럼 예상되는 Peak 상황에서는:
AI OFF
Heavy Report OFF
Worker 조정
Cache Warm
등을 미리 적용할 수도 있다.
예:
NORMAL
PEAK_EVENT
Config를 둘 수 있다.
Runbook 형태로 준비해도 충분하다.
1. DB 상태 확인
2. Cache Warm
3. Low Priority Job Pause
4. Export 제한
5. Notification Worker 확인
6. Dashboard Monitoring
7. Event 종료 후 정상화
이다.
예상 Traffic 직전에 App Server를 미리 한 단계 늘리는 전략도 있다.
이벤트 시간이 명확하면:
오픈 30분 전 Scale Up
종료 후 Scale Down
같은 방식이다.
Backlog가 남아 있을 수 있다.
Queue 정상화 후 Scale Down한다.
1006과 연결된다.
신규 Instance가:
READY
상태가 된 뒤 Traffic을 보낸다.
Cold Cache 때문에 DB Traffic이 증가할 수 있다.
필요한 Hot Data만 미리 준비할 수 있다.
Jitter/순차 시작을 고려한다.
Instance를 줄이기 전에:
Readiness OFF
↓
Drain
↓
Terminate
한다.
1006과 연결된다.
Active Job을 안전하게 넘긴다.
예:
광고 Traffic 급증
↓
DB Connection Pool 포화
↓
API p95 4초
↓
Client Retry
↓
Traffic 더 증가
이다.
1. Retry Storm 확인
2. Low Priority 기능 제한
3. Rate Limit
4. Heavy Query 차단
5. 필요 시 Scale
6. Queue/DB 안정화
순이다.
원인이:
Retry Loop
라면 Scale이 공격 Traffic을 더 많이 받아주는 결과가 될 수도 있다.
질문:
어떤 Resource가 먼저 포화됐나?
사전에 알 수 있었나?
Alert가 있었나?
Load Test가 현실적이었나?
Headroom은 충분했나?
Scale보다 Optimization이 나았나?
이다.
SLO 위반이 반복되면:
신기능보다 성능 개선 우선
으로 전환할 수 있다.
Capacity 부족은 단순 Infra 이슈가 아니라 Product Delivery 우선순위에도 영향을 준다.
트래픽이 작은 서비스라면 매주 볼 필요는 없다.
예:
월 1회
큰 Release 전
마케팅 Event 전
정도로 충분할 수 있다.
예:
AI 분석
대형 Export
실시간 상태 조회
복잡 Search
등이다.
Current Load
Peak Load
SLO
Headroom
Top Bottleneck
Growth Trend
Recommended Action
정도로 유지한다.
API p95/p99
DB Query Latency
DB Connection
Queue Depth/Age
Metric 확보.
대표 Endpoint 선정:
상품 목록
상품 상세
관리자 주문 목록
검색
이다.
Staging Baseline Load Test.
병목 1개 수정.
예:
Index
N+1
Pagination
Cache
이다.
같은 Scenario 재테스트.
Before/After 비교.
Export/Notification/AI Worker Capacity를 별도로 측정.
사전예약 같은 Peak Event 전:
Spike Test
Peak Runbook
을 준비한다.
Kubernetes HPA
Multi-region Autoscaling
Database Sharding
복잡한 Read Replica Routing
Service Mesh Capacity Control
자동 AI Infra Scaling
까지는 필요 없다.
1. Query 개선
2. Cache
3. Worker Concurrency 조정
4. Vertical Scale
5. API/Worker Process 분리
6. Horizontal Scale
7. Read Replica 등
순서로 보는 것이 현실적이다.
실제 Bottleneck에 따라 바뀐다.
측정 없는 Scaling 금지
병목 없는 Optimization 금지
한 번에 하나씩 변경
변경 후 재측정
이다.
현재 React + NestJS + Prisma + PostgreSQL + AWS 프로젝트를
Capacity Planning 관점에서 분석해줘.
코드를 바로 수정하지 말고
현재 Architecture와 병목 후보를 먼저 파악한다.
목표는 대규모 분산 시스템을 만드는 것이 아니라,
- 현재 어디가 병목이 될 가능성이 있는지
- 어떤 Metric이 부족한지
- Load Test를 어디부터 해야 하는지
- 언제 Vertical / Horizontal Scaling이 필요한지
를 현실적으로 판단하는 것이다.
다음 영역을 검토한다.
1. NestJS API
2. Prisma Query
3. PostgreSQL Connection Pool
4. 관리자 Order Search
5. Product Read
6. Search
7. Export Worker
8. Notification Worker
9. Scheduler
10. AI / Local LLM Worker
11. Redis / Queue가 있다면 해당 Resource
12. S3 / CloudFront
각 영역마다 다음 형식으로 작성한다.
## Component
## Resource Characteristic
- CPU-bound
- Memory-bound
- DB-bound
- I/O-bound
- External API-bound
복수 가능.
## 현재 병목 후보
실제 코드에서 확인되는 내용만 작성한다.
## 필요한 Metric
## Scale 전에 해야 할 Optimization
## Scale 전략
- No Action
- Optimize
- Vertical Scale
- Horizontal Scale
- Worker Scale
- DB Scale
## Priority
P0 / P1 / P2
특히 다음을 찾아줘.
- N+1 Query
- Missing Pagination
- 과도한 include/select
- 긴 Transaction
- Connection Pool 위험
- 대량 Memory Load
- CPU-heavy 작업이 API Process에 있는지
- Background Job으로 보내야 할 작업
- Worker Concurrency가 명시되어 있는지
- External Provider Limit보다 Worker 처리량이 큰지
- Local State 때문에 Horizontal Scale이 어려운지
실제 Traffic Metric이 없으면
몇 RPS까지 버틸 수 있다고 추정하지 않는다.
마지막에는
현재 구조에서 가장 ROI가 높은
Capacity 개선 5개만 우선순위로 정리해줘.
현재 프로젝트를 위한
Staging Load Test Plan을 작성해줘.
Production 실제 고객 데이터는 사용하지 않는다.
목표는 최대 TPS를 자랑하는 것이 아니라
Latency/Error/Saturation이 급격히 증가하는 지점을 찾는 것이다.
우선 Test 대상:
1. Product List
2. Product Detail
3. Search
4. Admin Order List
5. Order Detail
6. Export Request
각 Scenario마다:
## 목적
## Test Data 조건
## Request Pattern
## Ramp Up
예:
낮은 부하
→ 예상 Peak
→ Peak의 1.5~2배
정확한 RPS는 실제 Baseline을 본 뒤 결정한다.
## 관찰 Metric
- RPS
- p50
- p95
- p99
- error rate
- CPU
- memory
- DB CPU
- DB connections
- query latency
- queue depth
- queue oldest age
## Stop Condition
예:
- error rate 급증
- p95 SLO 초과
- DB Connection Pool 포화
- CPU 장시간 90% 이상
- Health 이상
## 예상 병목 후보
## Test 후 확인사항
Cache 대상 Endpoint는
Warm Cache / Cold Cache Scenario를 나눈다.
Admin Search는
단일 Query만 반복하지 않고
다양한 Filter/Search/Sort 조건을 사용한다.
Write API 테스트는
Test DB와 더미 데이터만 사용한다.
현재 Queue / Worker를 대상으로
Capacity Test Plan을 작성해줘.
대상:
- Notification
- Export
- Webhook
- Workflow
- AI Task
각 Worker에 대해:
## Capacity Unit
예:
messages/sec
jobs/min
runs/hour
## Current Concurrency
## Job Duration 측정 방법
## Downstream Dependency
## External Rate Limit
## DB 사용량
## Queue Lag SLO
## Load Test 방식
## Scale-out 가능 여부
## Scale-out 시 위험
특히 다음을 확인한다.
1. Worker를 늘리면 DB Connection이 얼마나 늘어나는지
2. External Provider Rate Limit을 넘지 않는지
3. Queue Depth 감소 속도
4. Oldest Job Age
5. Retry Storm 발생 여부
6. Controlled Drain이 가능한지
7. Worker 종료 후 Resume 가능한지
결과에서
'Worker를 늘리면 해결되는 병목'과
'Worker를 늘리면 오히려 악화되는 병목'을
분리해서 설명해줘.
# Capacity Review
## 1. 환경
Application
DB
Queue
Cache
Worker
## 2. Current Production Load
Average RPS
Peak RPS
Peak Orders
Queue Throughput
## 3. Current SLO
Availability
p95 Latency
Queue Lag
## 4. Load Test
Scenario
Traffic
Duration
Dataset
## 5. Result
p50
p95
p99
Error Rate
CPU
Memory
DB CPU
Connections
## 6. Saturation Point
## 7. Primary Bottleneck
## 8. Secondary Bottleneck
## 9. Improvement
## 10. Retest Result
## 11. Current Safe Capacity
## 12. Headroom
## 13. Growth Risk
## 14. Recommended Action
Optimize / Scale / No Action
## 15. Next Review
# Capacity Scaling Runbook
## 1. 증상 확인
- Traffic 증가?
- Latency 증가?
- Error 증가?
- Queue Lag 증가?
## 2. 최근 변경 확인
- Release
- Migration
- Feature Flag
- Traffic Campaign
## 3. 병목 확인
- Application CPU
- Memory
- DB CPU
- DB Connections
- Slow Query
- Queue
- External Provider
## 4. Regression 여부
최근 배포 이후 발생했다면
Scale보다 Rollback/Hotfix 우선 검토.
## 5. Optimization 가능 여부
- Index
- Query
- Cache
- Pagination
- Concurrency
## 6. Scale 결정
Application / DB / Worker 중
실제 병목 Resource만 조정.
## 7. 한 단계 변경
한 번에 여러 Component를 확대하지 않는다.
## 8. Health 확인
Readiness
Error Rate
Latency
## 9. 재측정
개선됐는지 확인.
## 10. 기록
변경 이유와 Before/After Metric 기록.
1005에서는:
너무 많은 요청이 들어왔을 때
어떻게 제한하고 격리할 것인가
를 다뤘다.
1006에서는:
현재 Instance가
일을 받을 준비가 되어 있는가
를 다뤘다.
1007에서는 그보다 한 단계 앞선 질문인:
그럼 우리 시스템은
실제로 어느 정도까지 처리할 수 있는가?
를 다뤘다.
가장 중요한 첫 번째 원칙은:
Capacity
≠
서버 CPU 사양
이다.
실제 Capacity는:
Application
DB
Connection Pool
Queue
Worker
Redis
External Provider
중 가장 먼저 포화되는 곳에서 결정된다.
따라서 성능 문제가 생겼다고:
EC2 Upgrade
부터 하면 안 된다.
먼저:
Measure
↓
Find Bottleneck
↓
Optimize
↓
Measure Again
순서로 간다.
특히 DB 병목에서는:
Slow Query
Index
N+1
Pagination
Long Transaction
을 먼저 확인한다.
좋은 Query 하나가 Infrastructure Upgrade보다 더 큰 Capacity 증가를 만들 수도 있다.
Load Test 역시:
최대 TPS 기록
이 목적이 아니다.
찾아야 하는 것은:
어느 부하에서
Latency가 급격히 상승하고
Error가 증가하며
어떤 Resource가 먼저 포화되는가
이다.
그래서:
10 RPS
↓
25
↓
50
↓
100
처럼 점진적으로 Ramp-up하면서:
p95/p99
Error Rate
CPU
Memory
DB Connections
Queue Lag
을 같이 본다.
Capacity가 부족하다고 판단됐을 때도 Scale 방법을 구분한다.
Vertical Scaling
=
한 서버를 크게
Horizontal Scaling
=
서버 수를 늘림
이다.
현재처럼 비교적 단순한 구조에서는:
Query Optimization
↓
Cache
↓
Worker Tuning
↓
Vertical Scale
이 먼저일 수 있다.
Horizontal Scale은 그 이후:
Stateless API
Shared Storage
Scheduler 중복 방지
Worker Idempotency
같은 준비가 필요하다.
또 App Instance를 많이 늘린다고 항상 좋아지는 것도 아니다.
App 10대
↓
DB Connection 10배
↓
DB 포화
가 될 수 있기 때문이다.
따라서:
App Capacity
DB Capacity
Worker Capacity
Provider Capacity
를 따로 보면서 전체 시스템을 맞춰야 한다.
특히 Worker에서는:
Queue가 밀린다
→ Worker 추가
로 바로 결론내리지 않는다.
원인이:
외부 Provider 지연
이라면 Worker 추가가 오히려 장애를 악화시킬 수 있다.
현재 프로젝트에서 가장 현실적인 접근은:
1. p95/p99 확보
2. DB Query Latency 확보
3. Queue Depth/Age 확보
4. 대표 Endpoint Load Test
5. 병목 한 개 수정
6. 동일 Scenario 재테스트
7. Before/After 기록
이다.
사전예약이나 대규모 광고처럼 Traffic Spike가 예상된다면:
Peak Event 전
Load Test
↓
Cache 확인
↓
Worker 확인
↓
Low Priority 기능 제한 준비
↓
필요하면 Pre-scale
하면 된다.
그리고 Scale은 성능 문제만이 아니라 비용 문제이기도 하다.
Infra 비용
개발 시간
운영 복잡도
를 모두 봐야 한다.
1인 개발 환경에서는:
복잡한 분산 Architecture로 월 2만원 아끼기
보다:
조금 더 큰 서버를 쓰고
운영 구조를 단순하게 유지
하는 것이 더 경제적인 경우도 충분히 있다.
전체 흐름을 연결하면:
Traffic
↓
Measure
↓
Load Test
↓
Saturation
↓
Bottleneck
↓
Optimize
↓
Retest
↓
Headroom 계산
↓
Scale 필요 여부 결정
↓
Guardrail 적용
↓
Observe
가 된다.
결국 Capacity Planning의 핵심은
“서버를 얼마나 크게 만들 것인가”가 아니라, 현재 시스템의 실제 한계와 병목을 숫자로 확인하고, 가장 작은 비용과 복잡도로 그 병목 하나를 제거한 뒤 다시 측정하는 것
이다.