Dev V1 병목 분석과 비용 - 100-hours-a-week/KTB4-2nd-Cloud GitHub Wiki

V1 병목 분석과 비용

V1을 배포하고 운영하면서 실제로 생긴 문제, 부하 시험에서 확인한 병목, 사용자가 늘면 운영 중 먼저 나타날 문제, 그리고 비용을 한 문서에 정리합니다. 세부 근거는 각 개발 문서와 트러블슈팅 기록에 있고, 이 문서는 그 결과를 묶어서 해석합니다.

V1 정식 운영은 2026년 10월 첫 주부터 약 2주 동안 진행합니다. 운영하면서 관찰한 값으로 이 문서를 계속 갱신합니다.

항목 내용
기준일 2026-10-04 (V1 정식 운영 시작 시점)
갱신 방식 매주 운영 관찰 기록에 한 줄씩 추가하고, 새 문제나 상태 변화가 있으면 해당 절을 갱신
관련 설계 EC2 + Docker Compose 초기 배포 설계, 컨테이너 기반 서비스 확장 및 운영 자동화 설계

1. V1 운영 중 실제로 겪은 문제

외부 요청 폭주로 로그인 불가 (9/29)

인증 없이 지도 조회를 반복하는 요청이 몰리면서 약 5분 동안 로그인이 되지 않았습니다. CPU는 44%로 여유가 있었지만 Nginx의 연결 자리 1,536개가 먼저 찼습니다.

V1은 모든 요청이 App EC2 한 대의 Nginx 하나로 들어옵니다. 이 진입점이 막히면 서버 자원이 남아 있어도 서비스 전체가 멈춘다는 걸 확인했습니다. 출처별 요청 제한은 아직 적용하지 않았습니다.

상태 원인 확인, 방어 설정 미적용
기록 2026-09-29 Nginx 동시 연결 고갈

배포가 진행 중인 사진 업로드를 끊음 (9/29)

팀원이 사진을 올리는 중에 배포를 실행했고, Backend 컨테이너가 교체되면서 마지막 업로드가 502로 끝났습니다.

V1은 서버 한 대에서 컨테이너를 바꿔 끼우는 방식이라, 진행 중인 요청을 다른 곳으로 넘길 수 없습니다. 여행 생성은 몇 분씩 이어지는 작업이라 배포 시점과 겹칠 가능성이 높습니다. Backend에 신규 접수 차단과 활성 세션 조회 API를 요청했고, 연결 전까지는 사용자가 적은 시간에 진행 중인 업로드를 확인하고 배포합니다.

상태 Backend Drain API 요청, 연결 전
기록 배포 중 사진 업로드 중단

여행 생성이 AI 단계에서 전부 실패 (9/24)

사진 업로드는 끝났는데 AI 분석 요청이 매번 422로 실패해서 여행이 만들어지지 않았습니다. Backend의 HTTP Client가 HTTP/2 업그레이드를 시도했고, HTTP/1.1만 받는 AI 서버가 이를 거절하면서 요청 본문이 비어서 도착했습니다.

Backend와 AI는 각자 정상이었고, 두 서비스가 만나는 지점에서 실패했습니다. 같은 시기 환경변수가 컨테이너에 전달되지 않아 장소 검색이 실패한 일, 마이그레이션 버전이 겹쳐 Backend가 뜨지 않은 일도 같은 성격이었습니다. V1에서 서비스를 멈춘 문제는 자원 부족보다 이런 경계에서 더 자주 생겼습니다.

상태 해결 (Backend HTTP/1.1 고정)
기록 BE에서 AI로 보낸 요청이 422로 실패

Worker 디스크 부족으로 배포 실패 (9/26)

새 AI 이미지를 받지 못해 배포가 실패했고, 배포 워크플로가 App과 Worker를 직전 성공 조합으로 되돌렸습니다. 모델을 포함한 AI 이미지가 커서, 이전 이미지가 쌓이며 Worker의 가용 공간이 7.7GB까지 줄어 있었습니다.

Worker는 작업이 있을 때만 켜지는 서버라 평소에 디스크 상태를 볼 기회가 적습니다. 배포가 성공한 뒤 사용하지 않는 이미지를 자동으로 지우도록 바꿨고, 자동 롤백이 실제 장애에서 동작한다는 것도 이때 확인했습니다.

상태 해결 (배포 후 미사용 이미지 자동 정리)
기록 배포 파이프라인

개발 서버

상태 {{상태}}
내용 {{개발 서버 관련 문제와 운영에서의 의미}}

정리

V1 운영 중 사용자 요청을 실패하게 만든 문제는 두 종류였습니다.

  • 단일 서버 구조에서 생긴 문제: 진입점이 하나라 연결 자리가 차면 전체가 멈추고, 컨테이너를 교체하면 진행 중인 요청이 끊김
  • 서비스 경계에서 생긴 문제: 각 서비스는 정상인데 HTTP 버전, 환경변수, 마이그레이션처럼 서로 맞물리는 지점에서 실패

실제 사용량이 적어서 서버 자원이 모자라 실패한 경우는 운영 중에는 없었습니다. 자원 쪽 한계는 외부 부하와 부하 시험에서 처음 드러났고, 2절에 정리했습니다.


2. 병목 지점

부하 시험에서 확인한 병목을 요약합니다. 시험 조건과 수치는 부하 테스트에 있습니다.

구분 결과
첫 실패 지점 Backend 사진 변환 접수 한도. 여행 생성이 겹치면 업로드가 500으로 끝남
자원 압박 조회는 연결 수(40 API RPS에서 TCP 151개, CPU 27%), 업로드와 사진 변환은 CPU(생성 중 App CPU 약 85%)
병목이 아니었던 곳 Nginx(시험 범위에서 연결 부족 없음), 읽기 경로(계획 40 API RPS 통과), AI Worker(접수된 작업 모두 완료)
측정하지 못한 것 Worker 작업이 겹친 적이 없어 Worker 처리량 한계는 미측정

외부 요청이 한 지도 API에 몰린 9/29 장애에서는 Nginx 연결 슬롯이 CPU보다 먼저 찼습니다. 부하 시험에서는 Nginx까지 가기 전에 Backend가 먼저 실패했습니다. 요청의 성격에 따라 먼저 차는 곳이 다릅니다.


3. 사용자가 늘면 어디서 먼저 막히나

부하 시험 결과와 실제 설정값을 같은 기준(150장 여행이 시간당 몇 건 들어오는가)으로 나란히 놓으면, V1이 어디까지 버티고 어디서 먼저 막히는지 보입니다.

3.1 한계가 몰려 있는 구간

150장 여행 유입 결과 근거
시간당 4건 V1 예상 피크 설계
시간당 12건 통과 혼합 한계 시험 3배수
시간당 16건 Backend 사진 변환 접수에서 여행 생성 50% 실패 혼합 한계 시험 4배수
시간당 17~20건 AI Worker 처리 상한 동시 1건 처리 설정, 1건 실행 약 3~3.5분
3~4배수 구간 App CPU 약 85% 혼합 한계 시험

V1의 한계는 예상 피크의 34배, 시간당 1220건이라는 좁은 구간에 몰려 있습니다. 그리고 Backend 사진 변환, AI Worker, App CPU라는 서로 다른 세 곳이 거의 같은 부하에서 한계에 닿습니다.

그래서 한 곳만 고쳐서는 여유가 크게 늘지 않습니다. Backend의 변환 접수 문제를 해결해도 바로 뒤에 시간당 17~20건의 Worker 한계가 있고, Worker를 늘려도 App CPU가 이미 85% 근처입니다.

V1 구조 안에서 설정을 조정하는 것으로는 예상 피크의 약 3배가 현실적인 상한입니다. 그 이상은 업로드와 AI 처리를 App에서 떼어내는 구조 변경이 필요하고, 이건 6절의 V2 설계가 다루는 범위입니다.

기준을 150장 여행으로 잡았기 때문에 사진이 적은 여행이 많으면 처리할 수 있는 건수는 더 늘어납니다. 운영 2주 동안 실제 여행의 사진 수 분포를 보고 이 구간을 다시 계산합니다.

3.2 운영 중 볼 신호

한계 구간에 다가가고 있는지는 아래 신호로 판단합니다.

신호 다가가고 있는 한계 볼 곳
시간당 여행 생성이 10건을 넘는 시간대가 생김 한계 구간 전체 Backend trip_creation 시간당 건수
업로드 500, failure_stage=derivative_create Backend 사진 변환 접수 Backend trip_creation 실패 단계
AI 작업 대기 시간이 늘고 대기열이 비지 않음 AI Worker 처리량 AI ai_worker_execution 대기 시간, /health의 queued
App CPU 80% 이상이 이어지고 추가 요금 발생 App CPU CloudWatch CPU, CPUSurplusCreditsCharged

여행 생성 실패는 HTTP 실패율로는 잘 보이지 않습니다. 4배수에서 HTTP 실패율은 0.54%였지만 여행 생성 실패율은 50%였습니다. 운영 중에는 여행 생성 결과를 기준으로 봅니다.

3.3 사용량과 무관하게 남아 있는 위험

사용자 수와 관계없이 지금도 일어날 수 있는 문제입니다.

  • 같은 계정의 연속 생성: 결과 저장 단계에서 잠금 대기로 실패. 시험에서 확인했고, 사진이 많은 사용자일수록 발생 가능성이 커짐 (부하 테스트)
  • 외부의 반복 요청, 배포 중 업로드 중단: 1절의 두 문제. 방어 설정과 Drain이 연결되기 전까지 같은 방식으로 다시 생길 수 있음

4. 비용

V1은 처리 한계까지 써도 월 약 $196으로 예산(월 30만 원, 약 $217) 안입니다. 사용자가 늘 때 먼저 문제가 되는 건 비용이 아니라 3절의 처리량입니다.

항목 월 비용
고정비 (App EC2, EBS, Public IPv4, Route 53) 약 $49
AI Worker 사용량 비례 (여행 1건당 약 $0.01~0.05)
상한 (Worker가 한 달 내내 처리) 약 $196

Worker는 한 대가 한 번에 1건만 처리해서, 사용자가 늘어도 Worker 비용은 한 달 내내 일하는 경우(약 $147)를 넘지 않습니다. 10월부터는 AWS Activate Credit $1,000이 적용됩니다.

여행이 띄엄띄엄 들어오면 Worker 비용의 대부분은 작업 뒤 유휴 대기 10분에서 나옵니다. 금액이 작아 지금 조정하지는 않고, 운영 중 여행이 들어오는 간격을 보고 판단합니다.

예상 밖으로 늘 수 있는 비용은 두 가지를 봅니다.

  • App CPU 추가 요금: unlimited 모드에서 여행 생성 중 CPU 약 85%
  • 삭제된 원본의 이전 버전: 원본 경로에 이전 버전 정리 규칙이 없어, 여행을 지워도 저장 비용이 줄지 않음

단가는 설계 문서의 2026년 9월 공개 가격 기준이고, 운영 중 실제 청구액으로 갱신합니다.


5. 운영 관찰 기록

운영 2주 동안 매주 한 줄씩 추가합니다. 1~4절의 상태와 수치는 이 기록을 근거로 갱신합니다.

기간 여행 생성 (성공 / 전체) 생성 실패 단계 조회 p95 5xx App CPU 최대 Worker 가동 시간 Credit 사용액 특이사항
{{10/5 ~ 10/11}}
{{10/12 ~ 10/18}}

운영 중 함께 보완할 것

지금 수집하는 지표로는 놓칠 수 있는 것들입니다. 3절의 신호를 제때 알아차리려면 운영 기간 안에 보완해야 합니다.

빈틈 영향 보완
단건 500은 5xx Alarm(5분 5건 이상)에 걸리지 않음 여행 하나가 실패해도 알림 없음 trip_creation 실패 기준 Alarm
결과 저장 실패가 AI_PROCESSING_FAILED로 반환됨 원인을 AI로 잘못 짚을 수 있음 Backend 오류 코드 분리 요청
Worker 메모리 지표 미수집 Worker 한계 판단 불가 Worker에 메모리 지표 추가
Backend 후처리 단계별 시간 없음 업로드 지연 원인을 단계별로 못 나눔 Backend 단계별 시간 로그 요청

갱신할 때 함께 확인할 것

  • 1절: 새로 생긴 문제와 해결된 문제
  • 3절: 시간당 여행 생성 최대치, 실제 여행의 사진 수 분포로 한계 구간 재계산
  • 4절: 실제 청구액과 Worker 가동 시간으로 비용 갱신
  • 4절: 여행이 들어오는 간격과 유휴 종료 시간 조정 여부

6. V2 설계와의 연결

3절에서 본 것처럼 V1의 한계는 Backend 사진 변환, AI Worker, App CPU가 거의 같은 지점에 몰려 있어서, 한 곳의 설정을 바꾸는 것으로는 여유가 크게 늘지 않습니다. V2 설계는 이 세 곳을 서로 떼어내는 방향입니다.

V1에서 막히는 곳 V2 설계의 대응
사진 전송과 변환이 App CPU를 점유 사진 전송을 Backend에서 분리하는 S3 직접 업로드
AI 대기 동안 긴 연결과 상태 확인 요청이 App을 점유 작업 Queue를 통한 비동기 전달, WebSocket 진행 알림
AI 처리량과 Backend 수명이 묶여 있음 작업 Queue로 대기와 처리를 Backend와 분리
단일 App, 배포 중 업로드 중단 컨테이너 실행 플랫폼과 요청 분산, Rolling 교체

운영 2주 동안 3.2절의 신호가 실제로 얼마나 나타나는지가 V2 전환 시점과 우선순위를 정하는 근거가 됩니다. 자세한 설계는 컨테이너 기반 서비스 확장 및 운영 자동화 설계에 있습니다.

⚠️ **GitHub.com Fallback** ⚠️