PHP 서비스 트래픽이 늘 때 확장하는 순서 — 측정부터 EC2 수평 확장까지

조회수 66

트래픽이 증가한다고 Redis, 로드 밸런서, 복제 DB와 큐를 한꺼번에 추가하면 운영 지점만 늘어날 수 있다. 확장은 현재 병목과 실패 조건을 측정한 뒤 가장 작은 변화부터 적용해야 한다.

1. 먼저 서비스 목표를 숫자로 정의

대상 API: GET /posts/{id}
목표 처리량:
p95 응답 시간:
허용 오류율:
동시 사용자:
테스트 데이터 크기:
실패로 보는 자원 한계:

예시 숫자를 그대로 운영 목표로 사용하지 않는다. 현재 정상 트래픽과 사용자 기대를 바탕으로 기준을 정하고 부하 테스트는 운영과 분리된 환경에서 수행한다.

k6 부하 테스트 실행 중 프로그레스바 화면
k6 실행 중 프로그레스바 화면이다. 워밍업(5 VU) → 목표 동시 사용자(20 VU) → 쿨다운 순으로 단계가 진행된다.

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
작업 큐응답과 긴 작업 분리중복 처리·재시도·순서

측정된 병목과 일치하지 않으면 추가하지 않는다. 특히 큐 작업은 멱등성과 실패 저장소가 없으면 요청을 잃거나 중복 실행할 수 있다.

k6 부하 테스트 기준선 — 처리량 p95 오류율 초기 측정값
기준선 측정값이다. 동시 사용자 20명, 2분 실행 기준으로 p95 43ms, 오류율 0%를 기록했다.

7. 단계별 전후 기록

변경 전/후 commit과 인프라 구성:
동일 부하 시나리오:
처리량, p50, p95, p99:
오류율:
EC2 CPU·메모리:
PHP-FPM queue:
DB 연결·slow query:
비용 변화:
새 장애 지점:

정리: 트래픽 대응은 도구를 나열하는 것이 아니라 목표 수치 설정, 병목 측정, 단일 서버 개선, 상태 분리, 두 인스턴스 장애 시험 순으로 진행한다.

댓글 0

  • 첫 번째 댓글을 남겨보세요.