트래픽이 증가한다고 Redis, 로드 밸런서, 복제 DB와 큐를 한꺼번에 추가하면 운영 지점만 늘어날 수 있다. 확장은 현재 병목과 실패 조건을 측정한 뒤 가장 작은 변화부터 적용해야 한다.
1. 먼저 서비스 목표를 숫자로 정의
대상 API: GET /posts/{id}
목표 처리량:
p95 응답 시간:
허용 오류율:
동시 사용자:
테스트 데이터 크기:
실패로 보는 자원 한계:
예시 숫자를 그대로 운영 목표로 사용하지 않는다. 현재 정상 트래픽과 사용자 기대를 바탕으로 기준을 정하고 부하 테스트는 운영과 분리된 환경에서 수행한다.
2. 한 요청의 시간을 구간별로 나누기
flowchart LR
A[Client] --> B[Nginx]
B --> C[PHP-FPM]
C --> D[MariaDB]
C --> E[외부 API]
전체 응답 시간만 보면 어디를 확장해야 하는지 알 수 없다. Nginx access log, PHP 처리 시간, DB slow log와 외부 API 시간을 같은 request ID로 연결한다.
3. 첫 단계: 낭비 제거와 상향 조정
- N+1 쿼리와 불필요한 전체 컬럼 조회를 찾는다.
- 실행 계획으로 느린 쿼리와 인덱스를 검증한다.
- PHP-FPM worker 수를 메모리 한도와 함께 조정한다.
- 정적 파일은 Nginx 또는 객체 저장소·CDN으로 분리한다.
- 짧은 피크라면 인스턴스 유형 조정 비용과 효과를 비교한다.
구조를 늘리기 전에 단일 서버에서 얻을 수 있는 명확한 개선을 적용하고 같은 부하 조건으로 재측정한다.
4. 두 번째 단계: 상태를 서버 밖으로 분리
EC2를 여러 대로 늘리려면 어느 서버가 요청을 받아도 결과가 같아야 한다.
- 업로드 파일을 특정 EC2 디스크에만 저장하지 않는다.
- 세션을 로컬 파일에만 두지 않거나 고정 세션의 한계를 문서화한다.
- 배포 버전과 환경 설정을 인스턴스마다 동일하게 만든다.
- 로드 밸런서가 사용할 헬스체크를 제공한다.
5. 세 번째 단계: 두 대로 확장하고 장애 시험
검증 시나리오
1. App A와 App B가 같은 릴리스를 제공한다.
2. 로그인 후 어느 인스턴스로 가도 세션이 유지된다.
3. 업로드한 파일을 양쪽 경로에서 읽을 수 있다.
4. App A를 중지하면 신규 요청이 App B로 간다.
5. 복구 후 healthcheck를 통과한 A만 다시 트래픽을 받는다.
서버 수가 두 배가 되어도 MariaDB가 병목이면 처리량은 늘지 않을 수 있다. 확장 후 DB 연결 수와 쿼리 시간을 다시 측정한다.
6. 캐시·복제·큐는 각각 다른 문제에 사용
| 도구 | 해결하려는 문제 | 새로 생기는 위험 |
|---|---|---|
| 캐시 | 반복 읽기와 계산 | 무효화·오래된 값 |
| 읽기 복제 | 읽기 DB 부하 | 복제 지연·read-after-write |
| 작업 큐 | 응답과 긴 작업 분리 | 중복 처리·재시도·순서 |
측정된 병목과 일치하지 않으면 추가하지 않는다. 특히 큐 작업은 멱등성과 실패 저장소가 없으면 요청을 잃거나 중복 실행할 수 있다.
7. 단계별 전후 기록
변경 전/후 commit과 인프라 구성:
동일 부하 시나리오:
처리량, p50, p95, p99:
오류율:
EC2 CPU·메모리:
PHP-FPM queue:
DB 연결·slow query:
비용 변화:
새 장애 지점:
정리: 트래픽 대응은 도구를 나열하는 것이 아니라 목표 수치 설정, 병목 측정, 단일 서버 개선, 상태 분리, 두 인스턴스 장애 시험 순으로 진행한다.
댓글 0