2.1. 단일 App 서버의 한계와 개선 - 100-hours-a-week/KTB4-13th-wiki GitHub Wiki
2. 기존 인프라 구조의 한계와 개선
2.1. 단일 App 서버
1. 문제 정의
V1은 하나의 t3.small App EC2에서 Nginx, Backend와 MySQL을 함께 실행합니다.
App EC2
├─ Nginx
├─ Backend
└─ MySQL
V2의 7년 차 목표는 누적 가입자 250만 명, MAU 100만 명, 평균 DAU 10만 명입니다. 평상시 Peak Traffic은 0.18 RPS에서 625 RPS로 증가합니다. 현재 구조에는 다음과 같은 한계가 있습니다.
- EC2 장애 시 Backend와 MySQL이 함께 중단됩니다.
- Recreate 배포 중에는 요청을 처리할 Backend가 없습니다.
- 트래픽이 증가해도 요청을 나눠 처리할 App 서버가 없습니다.
- Backend와 MySQL이 자원을 공유해 각각 확장하기 어렵습니다.
- 서버 수가 고정되어 있어 트래픽 변화에 대응하기 어렵습니다.
정적 화면은 CloudFront와 S3에서 계속 제공할 수 있지만, App EC2가 중단되면 로그인·검색·리뷰·장바구니·주문·결제 등의 API는 사용할 수 없습니다.
현재 App EC2는 전체 API의 단일 장애 지점(SPOF)이며, Backend와 MySQL이 결합되어 있어 확장에도 한계가 있습니다.
2. Scale-Up과 Scale-Out 비교
| 기준 | Scale-Up | Scale-Out |
|---|---|---|
| 확장 방법 | 기존 EC2의 사양을 높임 | 같은 역할의 App EC2를 추가함 |
| 트래픽 증가 | 한 서버의 사양으로 대응 | 서버를 추가해 전체 처리량을 늘림 |
| 확장 범위 | 단일 인스턴스의 최대 사양에 제한됨 | 서버 수를 늘려 단계적으로 확장 가능 |
| 장애 영향 | 한 대만 운영하면 전체 Backend 중단 | 다른 서버가 요청을 이어서 처리 가능 |
| 배포 | 대체 서버가 없으면 배포 중 중단 | 일부 서버를 유지하며 순차 배포 가능 |
| 확장·축소 | 사양 변경 작업이 필요함 | 서버 수를 기준으로 조절 가능 |
| 비용 | 큰 사양을 실행하는 동안 같은 비용 발생 | 추가 서버와 로드밸런서 비용 발생 |
| 운영 | 비교적 단순함 | 요청 분산과 여러 서버 관리가 필요함 |
2.1. Scale-Up만으로 부족한 이유
Scale-Up은 기존 EC2의 CPU와 메모리를 늘리는 가장 단순한 확장 방법입니다. 현재 서버의 자원만 부족하다면 구조를 크게 바꾸지 않고 처리량을 높일 수 있습니다.
하지만 App 서버가 한 대인 상태에서는 다음 문제가 남습니다.
- EC2 장애 시 전체 Backend가 중단됩니다.
- 배포 중 요청을 처리할 대체 서버가 없습니다.
- 확장 범위가 단일 인스턴스의 최대 사양에 제한됩니다.
- Peak Traffic에 맞춘 사양을 트래픽이 적은 시간에도 유지해야 합니다.
북적북적은 로그인과 검색뿐 아니라 장바구니·주문·결제를 제공합니다.
App 서버가 중단되면 주문을 진행하거나 결제 결과를 확인할 수 없습니다. 서비스 규모가 커질수록 같은 시간의 중단도 더 많은 주문 실패와 매출 손실로 이어질 수 있습니다.
따라서 V2에서는 비용 효율성보다 가용성·복구성을 우선합니다. 서버 한 대의 처리량만 높이고 단일 장애 지점을 남기는 Scale-Up만으로는 이 요구사항을 충족하기 어렵다고 판단했습니다.
EC2 장애가 자주 발생한다고 가정하는 것은 아닙니다. 다만 현재 구조에서는 한 번의 장애만으로 로그인·검색·주문·결제 API가 모두 중단됩니다. 커머스 서비스에서 이 영향 범위가 큰 것이 문제입니다.
2.2. Scale-Out이 필요한 이유
Scale-Out은 같은 역할의 App 서버를 여러 대 실행하고 요청을 나눠 처리하는 방식입니다.
북적북적은 사용자가 도서를 검색하고 리뷰를 비교한 뒤 장바구니와 결제로 이동하는 흐름을 가집니다. 이 과정에서 서버가 중단되면 탐색이 끊기고 구매 포기로 이어질 수 있으므로, 일부 App 서버에 문제가 생겨도 사용자 흐름이 이어져야 합니다.
- 한 App 서버가 중단돼도 다른 서버가 요청을 처리할 수 있습니다.
- 일부 서버를 유지한 상태에서 나머지 서버를 순차적으로 배포할 수 있습니다.
- 트래픽이 증가하면 서버를 추가해 전체 처리량을 높일 수 있습니다.
- 트래픽이 감소하면 불필요한 서버를 줄일 수 있습니다.
- 한 서버의 최대 사양에 의존하지 않고 서비스 성장에 맞춰 확장할 수 있습니다.
여러 서버를 사용하려면 요청을 정상 서버로 분산하고, 비정상 서버를 요청 대상에서 제외해야 합니다.
3. Single-AZ와 Multi-AZ 비교
Scale-Out을 적용한 뒤에는 여러 App EC2를 같은 AZ에 둘지, 서로 다른 AZ에 나눌지 결정해야 합니다.
V2의 가용성 목표는 하나의 EC2 또는 AZ가 중단돼도 App 서비스를 계속 제공하는 것입니다.
| 기준 | Single-AZ | Multi-AZ |
|---|---|---|
| 서버 배치 | App EC2 2대를 같은 AZ에 배치 | App EC2 2대를 서로 다른 AZ에 배치 |
| 개별 EC2 장애 | 남은 EC2에서 요청 처리 | 남은 EC2에서 요청 처리 |
| AZ 단위 장애 | App EC2 전체가 영향을 받음 | 정상 AZ의 EC2에서 요청 처리 |
| EC2·EBS 기본 비용 | EC2 2대 비용 | 같은 사양의 EC2 2대라면 동일 |
| 전체 운영 비용 | 상대적으로 낮음 | 로드밸런서·교차 AZ 전송·NAT·모니터링 등 추가 가능 |
| 추가 부담 | 구성이 단순함 | AZ별 Subnet·라우팅·장애 전환 구성 필요 |
Single-AZ에 App EC2를 두 대 배치하면 개별 EC2 장애와 순차 배포에는 대응할 수 있습니다. 하지만 두 서버가 같은 장애 범위에 있어 해당 AZ에 문제가 생기면 App 계층 전체가 중단됩니다.
Multi-AZ는 가용성을 위해 유지할 EC2 두 대를 서로 다른 AZ에 배치하는 방식입니다. 같은 수와 사양의 EC2·EBS를 사용한다면 기본 컴퓨트 비용은 Single-AZ와 같지만, 전체 비용까지 같지는 않습니다. 로드밸런서, AZ 간 데이터 전송, AZ별 NAT Gateway, 로그·모니터링과 추가 운영 작업이 구성에 따라 더해집니다.
북적북적의 사용자 흐름은 한 번의 요청으로 끝나지 않습니다. 사용자는 로그인 후 검색이나 AI 추천을 이용하고, 여러 도서의 상세와 리뷰를 비교한 뒤 장바구니·주문·결제로 이동합니다. 대표 흐름에는 세션당 약 816회의 백엔드 요청이 발생하며, 일반 탐색과 구매 과정은 약 2030분 동안 이어집니다.
모든 App EC2가 같은 AZ에 있으면 이 과정에서 AZ 장애가 발생했을 때 로그인·검색·리뷰·장바구니·주문·결제 API가 함께 중단됩니다. 사용자는 진행 중이던 탐색과 구매를 이어갈 수 없으며, 장애가 복구되더라도 검색 조건이나 장바구니·결제 상태를 다시 확인해야 할 수 있습니다.
Multi-AZ는 하나의 AZ 장애가 App 계층 전체와 사용자 흐름의 중단으로 이어지는 것을 막습니다. App EC2를 서로 다른 AZ에 배치하면 한 AZ가 중단돼도 정상 AZ에서 도서 탐색과 주문·결제 API를 계속 제공할 수 있습니다.
북적북적은 도서 구매 제휴수수료로 매출을 얻으므로 App 계층의 장애는 단순한 접속 오류가 아니라 구매 기회의 손실로 이어집니다. 7년 차 목표 매출을 월 1억 5천만 원으로 계산하면 분당 기대 매출은 다음과 같습니다.
분당 기대 매출
= 150,000,000원 ÷ (30일 × 24시간 × 60분)
= 약 3,472원/분
AZ 장애로 주문·결제 API가 중단된 시간이 T분이면 직접 매출 기회 손실의 단순 추정값은 다음과 같습니다.
직접 매출 기회 손실
= 3,472원 × T분
실제 손실은 사용자가 장애 후 다시 구매하지 않는 비율, 결제 재시도 실패, 고객 문의와 신뢰 하락까지 포함하므로 이 계산보다 커질 수 있습니다. Multi-AZ의 추가 비용은 다음처럼 장애 감소 효과와 비교합니다.
월 Multi-AZ 추가 비용
= 추가 EC2·EBS + 로드밸런서·NAT·교차 AZ 전송·모니터링 + 추가 운영 비용
손익분기 중단 감소 시간(분/월)
= 월 Multi-AZ 추가 비용 ÷ 3,472원
Single-AZ의 App EC2 1대를 Multi-AZ의 2대로 늘릴 때 추가되는 최소 컴퓨트 비용은 다음과 같습니다.
추가 EC2·EBS 비용
= EC2 $18.72 + gp3 $2.74
= $21.46/월
환율을 $1=1,400원으로 가정하면 다음과 같습니다.
월 추가비용 = $21.46 × 1,400원 = 약 30,044원
손익분기 중단 감소 시간 = 30,044원 ÷ 3,472원/분 = 약 8.7분/월
즉, EC2·EBS 추가 비용만 고려하면 한 달에 8.7분 이상의 장애를 줄일 때 직접 매출 기준으로 비용을 회수할 수 있습니다. 이는 로드밸런서·NAT·데이터 전송·모니터링 비용을 제외한 최소 계산이며, 실제 예산에는 아래 항목을 추가합니다.
AZ 장애 지속시간은 일정하지 않습니다. AWS가 공개한 단일 AZ 장애 사례 중에는 약 11시간 동안 EC2·EBS 영향이 지속된 경우도 있습니다(AWS 장애 보고서). 이 시간이 모두 매출 손실로 이어진다고 단정할 수는 없지만, App 계층이 계속 중단되면 단순 직접 매출 손실만 약 3,472원 × 660분 = 2,291,520원입니다. 최소 추가비용 약 3만 원과 비교하면, 주문·결제 서비스를 제공하는 북적북적에서는 Multi-AZ 비용을 부담할 근거가 있습니다.
Multi-AZ 전환 시 비용 항목은 다음과 같습니다.
| 추가 항목 | 산정 기준 | 현재 가정에서의 처리 |
|---|---|---|
| App EC2 | 다른 AZ에 추가 인스턴스 1대 | $18.72/월 |
| EBS | 추가 EC2의 gp3 30GB | $2.74/월 |
| 로드밸런서 | 선택한 방식의 시간당·사용량 요금 | 요청량과 연결 수로 별도 산정 |
| NAT Gateway | AZ별 Gateway 시간 + 처리 데이터 | Private Subnet의 외부 통신 사용량으로 별도 산정 |
| 교차 AZ 데이터 전송 | AZ 사이를 오가는 데이터 | 실제 통신 경로와 전송량으로 별도 산정 |
| 로그·모니터링 | 대상 수와 수집량 증가 | CloudWatch 사용량으로 별도 산정 |
따라서 현재 문서에서 확정할 수 있는 Multi-AZ 최소 추가비용은 App EC2와 EBS의 $21.46/월이며, 실제 예산에는 선택한 로드밸런서·NAT·전송·모니터링 사용량을 더해 계산합니다.
3.1. 두 개 AZ를 선택한 이유
AZ 장애는 빈번하게 발생하는 장애는 아닙니다. Multi-AZ를 구성하는 목적은 모든 장애 상황에서 동일한 처리 용량을 유지하는 것이 아니라, 하나의 AZ가 App 계층 전체의 단일 장애 지점이 되는 것을 막는 데 있습니다.
두 개 AZ에 App EC2를 한 대씩 배치하면 한 AZ가 중단돼도 다른 AZ에서 도서 탐색과 주문·결제 API를 계속 제공할 수 있습니다. 남은 서버는 평상시 Peak 625 RPS를 처리할 수 있어야 합니다.
세 개 AZ를 사용하면 장애 이후에도 두 대의 서버가 남아 처리 여유와 이중화를 유지할 수 있지만, 이를 위해 평상시 App 서버 한 대의 비용을 추가로 부담해야 합니다.
현재 서비스의 목표는 장애 시 구매 흐름을 완전히 중단하지 않는 것이므로, 세 번째 서버를 상시 유지하지 않고 두 AZ를 기본 구성으로 사용합니다.
4. Multi-AZ에서 App을 고정 운영하는 경우
가용성을 확보하는 가장 단순한 방법은 두 AZ에 App EC2를 한 대씩 두는 것입니다. 한 EC2나 AZ에 문제가 생기면 다른 AZ의 서버가 요청을 처리할 수 있습니다.
하지만 두 대를 고정하는 것만으로 트래픽 변화까지 대응할 수 있는 것은 아닙니다.
- 한 서버가 중단되면 남은 서버 한 대가 전체 요청을 처리해야 합니다.
- 서버 장애와 Peak Traffic이 겹치면 처리 용량이 부족할 수 있습니다.
- 두 서버의 처리량을 넘는 요청이 들어오면 직접 서버를 추가해야 합니다.
- 장애 서버를 대신할 EC2도 직접 생성하고 설정해야 합니다.
장애 상황에도 Peak Traffic을 처리하도록 Scale-Up으로 보완하려면 두 EC2 모두 전체 Peak를 감당할 수 있는 사양으로 높여야 합니다.
그러나 북적북적은 점심 12:00~13:00과 저녁 18:00~23:00에 트래픽이 집중될 것으로 예상하므로, 큰 EC2를 계속 실행하면 나머지 시간에는 사용하지 않는 자원이 남습니다.
EC2는 CPU 사용률이 아니라 실행 시간과 인스턴스 사양을 기준으로 과금됩니다.
반대로 작은 EC2 두 대만 유지하면 집중 시간이나 장애 상황에서 처리 용량이 부족할 수 있습니다. 따라서 평상시에는 가용성에 필요한 최소 서버를 유지하고, 트래픽이 증가하거나 서버가 중단되면 필요한 만큼 서버를 추가할 방법이 필요합니다.
이를 위해 부하에 따라 App 실행 수를 자동으로 늘리거나 줄이는 Auto Scaling을 고려합니다.
5. App 실행 및 확장 방식 비교
Auto Scaling을 구성하는 방법은 무엇을 늘릴 것인지에 따라 나뉩니다.
비교할 방식은 ASG + EC2, ECS on EC2, ECS Fargate입니다.
| 방식 | 늘리는 단위 | 서버 관리 | 특징 |
|---|---|---|---|
| ASG + EC2 | EC2 | 팀이 관리 | 서버와 Backend 실행 수가 함께 증가 |
| ECS on EC2 | 컨테이너와 EC2 | 팀이 관리 | ECS가 컨테이너를 관리하고 ASG가 EC2를 관리 |
| ECS Fargate | 컨테이너 | AWS가 관리 | EC2를 직접 운영하지 않고 컨테이너만 관리 |
ASG + EC2는 Backend가 실행된 서버를 한 대씩 추가하는 방식입니다. ECS on EC2는 Backend 컨테이너와 이를 실행할 EC2 용량을 각각 관리합니다. ECS Fargate는 Backend 컨테이너만 관리하고 기반 서버 운영은 AWS에 맡깁니다.
5.1. ASG + EC2
ASG + EC2는 EC2를 확장 단위로 사용하는 방식입니다. 각 EC2에서 Backend 컨테이너를 실행하고, ASG가 필요한 EC2 수를 유지합니다.
V1에서는 서버가 부족하거나 중단되면 운영자가 EC2를 생성하고 Backend를 다시 실행해야 합니다. ASG를 사용하면 정해진 범위 안에서 EC2 수를 조절하고, 비정상 EC2를 같은 설정의 새 EC2로 교체할 수 있습니다. 따라서 두 AZ에 필요한 서버 수를 유지하면서 트래픽 증가와 서버 장애에 대응할 수 있습니다.
EC2 단위의 확장과 장애 교체를 자동화하면서, Backend 컨테이너 실행은 별도의 운영 설정으로 통제할 수 있다는 점이 장점입니다.
반면 ASG가 직접 관리하는 대상은 EC2입니다. Backend 컨테이너의 실행과 재시작, 로그 수집, 상태 확인과 배포 절차는 팀이 구성해야 합니다. 운영체제와 Docker의 보안 패치도 직접 관리해야 하므로 서버 운영 부담은 남습니다.
단점은 EC2 상태와 컨테이너 상태가 분리된다는 점입니다. EC2는 정상이어도 Backend 컨테이너가 중단될 수 있고, EC2가 교체된 뒤 컨테이너가 정상 배포되지 않을 수 있습니다. 서버 수가 늘어나면 배포 버전, 환경변수와 로그 수집 상태를 서버별로 확인해야 합니다.
새 EC2가 요청을 처리하려면 인스턴스 생성, OS 부팅, Backend 실행과 상태 확인을 거쳐야 하므로 확장에 시간이 걸립니다. 새 서버가 준비될 때까지는 기존 서버가 요청을 처리해야 하며, 가용성을 위해 유지하는 최소 EC2 비용도 계속 발생합니다.
5.2. ECS on EC2
ECS on EC2는 EC2 위에서 컨테이너를 실행하되, 컨테이너의 배치와 상태를 ECS가 관리하는 방식입니다. ECS에서 컨테이너 실행 단위를 Task라고 하며, ECS Service는 필요한 Task 수를 유지하고 비정상 Task를 새 Task로 교체합니다.
Capacity Provider는 ECS의 Task 수요와 ASG의 EC2 용량을 연결합니다. 관리형 확장을 사용하면 새 Task를 배치할 공간이 부족할 때 ASG에 EC2 확장을 요청합니다.
Backend 컨테이너 수 증가
→ ECS가 실행 공간 확인
→ 공간이 부족하면 ASG가 EC2 추가
→ 새 EC2에 Backend 컨테이너 배치
ECS on EC2를 사용하면 종료된 Backend Task를 자동으로 교체하고, 같은 설정으로 여러 EC2에 배치할 수 있습니다. 새 버전도 Task 단위로 순차 배포할 수 있어 컨테이너의 배포와 상태 관리를 자동화하기 좋습니다.
반면 ECS는 Task 수를, ASG는 EC2 수를 관리하므로 두 계층의 용량과 확장 상태를 함께 확인해야 합니다. ECS Cluster, Service와 Capacity Provider 설정이 추가되지만 EC2와 운영체제 관리도 그대로 남습니다.
북적북적의 App 계층에는 Backend 한 종류만 실행되지만, 같은 Backend Task를 여러 개 실행해 EC2의 남는 CPU와 메모리에 배치할 수 있습니다. 따라서 반드시 Task 하나가 늘 때마다 EC2도 한 대씩 추가되는 것은 아닙니다. 기존 EC2에 여유가 있으면 그 안에 Task를 먼저 배치하고, 공간이 부족할 때 EC2를 추가할 수 있습니다.
다만 ECS on EC2도 EC2 기동 지연이 완전히 사라지는 것은 아닙니다.
- 기존 EC2에 Task를 배치할 여유가 있으면 새 Task만 실행하므로 비교적 빠르게 확장할 수 있습니다.
- 여유 용량이 없으면 ASG가 새 EC2를 생성하고, OS 부팅과 ECS 등록이 끝난 뒤 Task를 배치해야 합니다.
- 이 경우 새 EC2가 준비될 때까지 Task는 대기하므로
ASG + EC2와 같은 기동 지연이 발생합니다.
ECS를 사용하면 Task 교체와 배포는 편해지지만, ECS의 Task 수와 ASG의 EC2 용량을 함께 관리해야 합니다. 또한 EC2와 운영체제의 패치 및 용량 관리도 그대로 남습니다.
단점은 관리 계층이 늘어난다는 점입니다. ECS Service의 Task 수가 충분해도 EC2 용량이 부족하면 Task가 실행되지 않고, EC2가 충분해도 실행 설정이나 상태 확인 설정이 잘못되면 서비스에 투입되지 않습니다. 따라서 Task·EC2·Capacity Provider의 상태를 함께 확인해야 합니다.
5.3. ECS Fargate
Fargate는 EC2를 직접 운영하지 않고 Backend 컨테이너를 Task 단위로 실행하는 방식입니다. 팀은 컨테이너 이미지와 CPU·메모리, 실행 수를 정하고 기반 서버와 OS는 AWS가 관리합니다.
ECS on EC2처럼 Task를 실행할 EC2 용량을 따로 관리하지 않아도 되므로 구조와 운영이 단순합니다. 인프라 담당자가 개발을 병행하는 북적북적의 운영 부담도 줄일 수 있습니다.
대신 정해진 CPU·메모리 조합에서 사양을 선택해야 하고 기반 서버를 직접 제어할 수 없습니다. 새 Task도 이미지 다운로드와 상태 확인을 거쳐야 하므로 바로 요청을 처리할 수 있는 것은 아닙니다. 또한 Backend를 계속 실행하면 트래픽이 적어도 지정한 자원에 대한 비용이 발생합니다.
단점은 상시 실행 서비스에서 비용 예측이 불리할 수 있다는 점입니다. Task 수를 줄이지 않는 한 사용량이 낮은 시간에도 동일한 CPU·메모리 비용이 발생하며, EC2처럼 남은 자원에 여러 컨테이너를 배치해 비용을 줄이기 어렵습니다. 네트워크·스토리지 설정도 Task 단위로 구성해야 하므로 대규모 실행에서는 관리 항목이 늘어날 수 있습니다.
5.4. 비용 비교
실행 단위 두 개를 30일 동안 유지하는 단순 계산을 기준으로 비교합니다. EC2와 ECS on EC2의 과금 구조는 EC2 요금과 ECS 요금을 참고했습니다. 아래 금액은 리전·트래픽·데이터 전송·로드밸런서·NAT·로그 비용을 제외한 기본 실행 비용이므로 전체 청구액이 아닙니다.
- 한 달:
30일 × 24시간 = 720시간 - EC2 기반 방식:
t3.small2대와 gp3 30GB씩 사용 - Fargate: 1 vCPU·2GB Task 2개 사용
| 비용 항목 | ASG + EC2 | ECS on EC2 | ECS Fargate |
|---|---|---|---|
| 컴퓨트 기본 비용 | EC2 2대 $37.44 |
EC2 2대 $37.44 |
Task 2개 $76.29 |
| 블록 스토리지 | gp3 $5.47 |
gp3 $5.47 |
포함되지 않음 |
| ECS Task 실행료 | 해당 없음 | 별도 없음 | 컴퓨트 비용에 포함 |
| 기본 월 비용 | $42.91 |
$42.91 |
$81.76 |
| EC2·OS 관리 | 직접 관리 | 직접 관리 | 관리하지 않음 |
| Task 배포·복구 | 별도 구성 | ECS Service 제공 | ECS Service 제공 |
| 컨테이너 운영 설정 | Docker·스크립트 직접 구성 | Cluster·Service·실행 설정·Capacity Provider 관리 | Task 설정만 관리 |
| 장애·배포 운영 공수 | 서버별 복구·배포 절차를 직접 관리 | ECS 정책과 EC2 용량을 함께 관리하지만 Task 교체·Rolling 배포는 표준화 | EC2 장애·OS 패치 부담이 없음 |
| 관리 비용 | 서버별 배포·복구·점검 시간 | ECS 설정·EC2 용량·Task 상태 점검 시간 | 서버 관리 대신 Task 운영 비용 |
위 금액은 특정 리전의 온디맨드 기준으로 계산한 기본 실행 비용이며, 로드밸런서·NAT·데이터 전송·로그 비용은 제외했습니다.
인스턴스 수와 사양이 같으면 ECS on EC2와 일반 EC2의 기본 컴퓨팅 비용은 동일합니다.
ECS on EC2는 별도 Task 실행료가 없지만 CloudWatch, 로드밸런서, NAT, 데이터 전송 등 부가 서비스 비용이 발생할 수 있습니다. ASG + EC2는 서버별 배포·복구 작업이 늘어나며, 컨테이너 장애나 배포 오류를 별도로 감지·복구해야 합니다.
ECS on EC2는 ECS 설정과 EC2 용량을 함께 관리하지만 Task 교체와 Rolling 배포를 표준화할 수 있습니다. ASG + EC2는 ECS 관리 항목이 없는 대신 서버별 배포·복구 공수가 증가합니다. ECS의 단점은 관리 계층이 늘고 Task와 EC2의 상태를 함께 확인해야 한다는 점입니다.
Fargate는 EC2와 운영체제를 직접 관리하지 않아 운영 부담이 작지만, Backend Task 두 개를 계속 실행하는 기준에서는 월 비용이 EC2 기반 방식보다 높습니다. V2는 App을 상시 운영하므로 Fargate를 제외하고, ASG + EC2와 ECS on EC2를 운영 방식과 자동화 범위로 비교합니다.
5.5. App 실행 방식 선택
ASG + EC2와 ECS on EC2는 모두 EC2에서 Backend를 실행하지만, 컨테이너를 관리하는 단위가 다릅니다.
| 기준 | ASG + EC2 | ECS on EC2 |
|---|---|---|
| 관리 단위 | EC2와 Docker 컨테이너 | ECS Task와 EC2 |
| 확장 | ASG가 EC2 수 조절 | ECS Service가 Task 수 조절, ASG가 EC2 용량 조절 |
| 장애 복구 | EC2 교체, 컨테이너 복구는 별도 구성 | Task와 EC2를 각각 교체 |
| 배포 | 스크립트·AMI·Instance Refresh 구성 | Task 단위 Rolling 배포 |
| 기본 비용 | EC2·EBS 비용 | 같은 EC2·EBS 사용 시 동일 |
ASG + EC2도 운영할 수 있지만 EC2 상태, 컨테이너 상태와 배포 버전을 별도로 관리해야 합니다.
북적북적은 검색·추천에서 도서 상세·리뷰, 장바구니·주문·결제로 이어지는 흐름을 제공합니다. 배포나 Backend 장애가 이 흐름을 끊으면 사용자는 구매를 포기하거나 결제를 다시 시도해야 합니다. 따라서 정상 Task를 유지하면서 비정상 Task만 교체하고, 새 버전이 Health Check를 통과한 뒤 요청을 받아야 합니다.
ECS on EC2는 ECS Service가 Task 유지와 Rolling 배포를 담당하고, Capacity Provider와 ASG가 Task와 EC2 용량을 연결합니다.
ECS는 EC2의 AMI·OS·용량과 ECS 설정을 모두 관리해야 합니다. 그러나 기본 EC2 비용은 ASG + EC2와 같고, 추가 비용은 주로 ECS 설정과 운영 공수에서 발생합니다. 북적북적은 탐색에서 주문·결제로 이어지는 서비스이므로 배포 실패나 컨테이너 장애가 구매 중단으로 이어질 수 있습니다. ECS Service의 Health Check, 비정상 Task 교체와 Rolling 배포로 이 중단 가능성을 줄이는 편이 운영 비용을 지불할 가치가 있습니다.
ECS on EC2에서 추가되는 비용은 다음과 같습니다.
- ECS Cluster·Service·실행 설정·Capacity Provider 설정과 변경 관리
- Task와 EC2 용량을 함께 확인하는 운영 시간
- CloudWatch 로그·메트릭, 로드밸런서·NAT·데이터 전송 사용료
- ECS 장애·배포 상태를 확인하기 위한 관측과 대응 절차
월 매출 1억 5천만 원 기준 분당 기대 매출은 약 3,472원입니다. App 계층 장애가 1시간 지속되면 직접 매출 기회 손실은 약 208,320원입니다.
3,472원 × 60분 = 208,320원
한 시간 장애를 예방할 수 있다면 위 비용을 부담할 근거가 있습니다. 결제 재시도·복구 작업·고객 이탈까지 고려하면 ECS on EC2를 선택합니다. 구체적인 Task·EC2 수량은 9장에서 산정합니다.
6. App과 AI ECS 사이징 및 Auto Scaling 전략
6.1. Task 처리량 기준
북적북적의 7년 차 평상시 Peak는 625 RPS이며, 이벤트 설계 기준은 1,250 RPS입니다.
App EC2는 t3.small을 기본 사양으로 사용합니다. 2 vCPU·2GiB 환경에서 Java·Spring Boot Backend와 ECS Agent를 실행할 수 있으며, 2GiB는 여유가 큰 사양이 아니므로 한 EC2에 Backend Task 하나만 배치합니다.
사이징 기준은 2 vCPU·2GB 환경의 Spring Boot·MySQL·JPA 공개 부하 테스트 사례를 참고합니다. 해당 사례에서 측정된 240 RPS를 초기 처리량 참고값으로 사용하고, 최종값은 실제 요청 시나리오로 검증합니다.
북적북적은 처리시간이 짧은 홈·상세 조회와 검색·리뷰·주문·결제를 같은 Backend에서 처리합니다. 요청 처리시간의 편차가 크면 평균 처리량에 여유가 있어도 느린 요청이 쌓이면서 응답시간이 증가할 수 있습니다.
북적북적은 조회·검색·리뷰·주문·결제가 섞여 요청별 처리시간의 편차가 있으므로, 최대 처리량을 100% 사용하지 않고 운영 여유를 둡니다. 동기식 요청은 최대 처리량의 60~70% 수준에서 운영 기준을 잡는다는 관련 자료를 참고해, 공개 사례의 240 RPS 중 70%를 초기 운영 기준으로 적용합니다.
Task당 운영 기준
= 240 RPS × 70%
= 168 RPS
따라서 초기 Task당 운영 기준은 168 RPS로 설정합니다. 실제 부하테스트 결과에 따라 이 기준과 Task 수를 조정합니다.
초기 배포에서는 t3.small 한 대에 App Task 하나만 배치합니다. 2GiB 메모리에서 여러 JVM을 실행하면 JVM Heap과 OS·ECS Agent가 사용할 메모리가 부족해질 수 있고, 한 EC2 장애가 여러 Task에 동시에 영향을 줄 수 있기 때문입니다. AI Server는 App Task와 같은 ECS Service에 넣지 않고 별도 Service로 분리합니다.
6.2. Task 수 산정
평상시 Peak 625 RPS에 필요한 Task 수는 4개입니다.
ceil(625 RPS ÷ 168 RPS)
= 4개
625 RPS ÷ 4개
= Task당 약 156 RPS
이벤트 설계 기준 1,250 RPS에 필요한 Task 수는 8개입니다.
ceil(1,250 RPS ÷ 168 RPS)
= 8개
1,250 RPS ÷ 8개
= Task당 약 156 RPS
| 구간 | 전체 트래픽 | Task 수 | Task당 트래픽 | AZ별 배치 |
|---|---|---|---|---|
| 평상시 Peak | 625 RPS | 4개 | 약 156 RPS | 2개 |
| 이벤트 | 1,250 RPS | 8개 | 약 156 RPS | 4개 |
트래픽이 두 배로 증가할 때 Task 수도 두 배로 늘려 Task당 부하를 같은 수준으로 유지합니다.
6.3. App과 AI Server를 분리하는 이유
App과 AI Server는 요청 특성과 필요한 자원이 다릅니다.
| 구분 | App Service | AI Server Service |
|---|---|---|
| 처리 방식 | ALB를 통한 동기 HTTP 요청 | ALB를 통한 동기 HTTP 요청과 외부 LLM API 호출 |
| 확장 기준 | RequestCountPerTarget, p95, CPU·메모리 | 요청 수, 응답시간, CPU·메모리 |
| 장애 영향 | 로그인·검색·주문·결제 요청 실패 | AI 추천·챗봇·임베딩 요청 실패 |
| 배치 대상 | 서로 다른 AZ의 EC2 | 서로 다른 AZ의 EC2 |
| 최소 운영 수 | 2 Task | 2 Task |
AI Server를 App과 같은 Service로 묶으면 AI 요청이 증가할 때 임베딩 모델과 외부 LLM API 호출이 App의 CPU·메모리·DB Connection을 잠식할 수 있습니다. 반대로 App 배포나 장애가 AI 요청까지 중단시키는 문제도 생깁니다. 따라서 ECS Cluster는 공유할 수 있지만, 서비스·실행 설정·자동 확장 정책·배포 단위는 분리합니다.
AI Server는 처음부터 App과 같은 수량으로 맞추지 않습니다. 임베딩 모델을 메모리에 로드하므로 App보다 큰 메모리가 필요하고, AI 요청량과 응답시간을 기준으로 별도 확장합니다.
6.4. Task 크기와 초기 배치 기준
Task 크기는 각 서비스가 실행되는 데 필요한 CPU와 메모리를 기준으로 정합니다.
| Task | 초기 CPU 예약 | 초기 메모리 예약 | 실행 환경 |
|---|---|---|---|
| App | 512 CPU units (0.5 vCPU) | 1,024 MiB | t3.small |
| AI Server | 1,024 CPU units (1 vCPU) | 3,072 MiB | t3.medium |
App Task는 Spring Boot 애플리케이션 실행에 512 CPU units / 1,024MiB를 할당합니다. 실제 부하 상황에서 CPU·메모리 사용량과 P95 응답시간을 확인해 조정합니다.
AI Server는 임베딩 모델을 Task 내부 메모리에 로드하고 외부 LLM API를 호출합니다. 따라서 초기 Task 크기는 1 vCPU / 3GiB로 설정하고, AI EC2는 t3.medium을 사용합니다. t3.medium 한 대에 AI Task 하나를 배치해 OS·ECS Agent와 요청 처리에 필요한 여유를 남깁니다.
6.5. 실행 수
App Service
| 항목 | 설정값 | 근거 |
|---|---|---|
| Min Task | 2개 | 두 AZ에 App Task를 하나씩 유지하기 위한 최소 수량 |
| Desired Task | 4개 | 평상시 Peak 625 RPS를 처리하기 위한 초기 운영 수량 |
| Max Task | 8개 | 이벤트 기준 1,250 RPS에 대응하기 위한 최대 수량 |
AI Server Service
| 항목 | 설정값 | 근거 |
|---|---|---|
| Min Task | 2개 | 두 AZ에 AI Task를 하나씩 유지하기 위한 최소 수량 |
| Desired Task | 2개 | 두 AZ에 하나씩 배치하기 위한 초기 운영 수량 |
| Max Task | 4개 | AI 요청량과 응답시간 증가에 대비한 최대 수량 |
App과 AI는 별도의 ECS Service로 운영합니다. App은 평상시 Peak 처리량을 기준으로 4개를 실행하고, 이벤트 상황에서는 최대 8개까지 늘립니다. AI Server는 2개로 시작하고, 요청량과 응답시간이 증가할 때 최대 4개까지 늘립니다.
6.6. ECS 배치전략
App과 AI는 각각 별도의 ECS Service로 운영합니다. 각 Service의 Task는 두 Availability Zone에 나누어 배치합니다.
배치 기준은 다음과 같습니다.
- 두 Availability Zone에 Task를 균등하게 나눕니다.
- 같은 AZ 안에서도 Task가 특정 EC2에 몰리지 않도록 여러 EC2에 나눕니다.
- 같은 Service의 Task가 하나의 EC2에 함께 배치되지 않도록 제한합니다.
ECS에서는 spread를 사용해 Task를 AZ와 EC2에 고르게 배치합니다. 또한 distinctInstance를 적용해 같은 Service의 Task가 하나의 EC2에 중복 배치되지 않도록 합니다.
이렇게 구성하면 특정 EC2나 AZ에 장애가 발생해도 모든 Task가 동시에 중단되는 위험을 줄일 수 있습니다. 다만 실행 가능한 EC2의 CPU와 메모리가 부족하면 새 Task가 바로 실행되지 않을 수 있으므로, Task를 늘릴 때는 EC2의 남은 자원도 함께 확인합니다.
6.7. Auto Scaling 기준
App과 AI는 요청 특성이 다르므로 서로 다른 기준으로 확장합니다.
App Service
App은 RequestCountPerTarget을 주요 기준으로 사용합니다. 평상시 Peak 625 RPS를 App Task 4개가 처리하면 Task 하나당 처리량은 약 156 RPS입니다.
625 RPS ÷ 4개
= Task당 약 156 RPS
Task당 운영 기준인 168 RPS에 가까워지면 App Task를 추가합니다. 다만 요청 수 하나만으로 판단하지 않고 다음 지표를 함께 확인합니다.
- Target당 요청 수
- CPU 사용률
- 메모리 사용률
- P95 응답시간
- HTTP 5xx 오류율
위 지표가 일정 시간 동안 계속 증가하면 App Task를 추가합니다. 반대로 지표가 안정적으로 낮아진 경우에만 Task를 줄이며, 최소 2개 아래로는 줄이지 않습니다.
App Task 수는 다음 범위 안에서 조정합니다.
최소 2개
평상시 4개
최대 8개
AI Server Service
AI Server는 App과 같은 기준을 사용하지 않습니다. AI 요청은 임베딩 모델과 외부 LLM API의 영향을 받기 때문에 다음 지표를 기준으로 확장합니다.
- AI 요청 수
- AI 응답시간
- CPU 사용률
- 메모리 사용률
- 외부 LLM API 응답 지연
- 처리 중인 요청 수
AI Server는 기본 2개로 운영합니다. 응답시간이나 메모리 사용량이 지속적으로 증가하면 최대 4개까지 늘립니다. AI 요청이 줄어들더라도 최소 2개는 유지합니다.
최소 2개
평상시 2개
최대 4개
자동 확장은 짧은 순간의 요청 증가만으로 바로 실행하지 않습니다. 관련 지표가 일정 시간 동안 기준을 초과할 때 Task를 추가하고, 지표가 일정 시간 안정된 뒤에만 Task를 줄입니다. 이를 통해 Task가 짧은 시간 동안 반복해서 늘고 줄어드는 현상을 줄입니다.
7. 장애 발생 시 가용성 유지 전략
7.1. Backend Task 장애
북적북적의 한 세션은 로그인, 검색, 도서 상세·리뷰 조회, 장바구니와 주문·결제로 이어집니다. 이 중간에 특정 Task가 중단되면 사용자는 검색 결과나 장바구니 화면에서 다음 단계로 이동하지 못할 수 있습니다. 따라서 장애 Task를 빠르게 요청 경로에서 제외하고, 다른 Task로 요청을 보내는 것이 필요합니다.
로드밸런서의 Health Check가 실패한 Task는 요청 대상에서 제외합니다. 정상 Task로만 요청을 전달하므로 장애 Task가 검색·리뷰·주문 요청을 계속 받지 않습니다.
ECS Service는 원하는 Task 수를 유지하도록 새 Task를 실행합니다. 새 Task가 Health Check를 통과한 뒤 요청 대상에 포함되므로 준비되지 않은 컨테이너가 트래픽을 받지 않습니다.
이를 위해 세션과 업로드 파일을 Task 내부에 저장하지 않습니다. 세션은 외부 저장소에 두고, 이미지는 S3에 저장해야 다른 Task로 요청이 전환돼도 사용자의 로그인 상태와 업로드 결과가 유지됩니다.
7.2. EC2 장애
EC2가 중단되면 해당 EC2에서 실행 중인 Backend Task도 함께 중단됩니다. 같은 EC2에 Backend와 다른 구성요소를 함께 배치한 V1에서는 이 장애가 로그인·검색·리뷰·주문·결제 전체의 중단으로 이어졌습니다. V2에서는 Task를 여러 EC2에 분산해 장애 범위를 한 실행 단위로 제한합니다.
Capacity Provider는 부족해진 Task 배치 용량을 확인하고, ASG가 새 t3.small을 실행하도록 연결합니다.
새 EC2가 ECS Cluster에 등록된 뒤 Backend Task를 배치하고, 로드밸런서 Health Check를 통과한 시점부터 요청을 전달합니다. 장애가 발생한 EC2를 복구하는 동안에도 다른 EC2의 Task가 요청을 처리합니다.
7.3. AZ 장애
평상시에는 두 AZ에 App Task를 하나씩 배치합니다. 한 AZ가 중단되면 다른 AZ의 App Task 하나가 요청을 계속 처리합니다.
AZ 장애 직후 운영 기준 용량
= 1개 × 168 RPS
= 약 168 RPS
이는 평상시 Peak 625 RPS 전체를 유지하는 용량은 아니므로 일부 요청의 응답시간이 증가하거나 일부 기능을 제한할 수 있습니다. 그러나 서비스 전체가 중단되는 대신 로그인·검색·도서 조회 같은 핵심 기능을 우선 제공할 수 있습니다. Capacity Provider와 ASG는 정상 AZ에 EC2와 Task를 추가해 처리 용량을 회복합니다.
7.4. 배포 중 가용성 유지
배포 중에는 기존 정상 Task를 유지한 상태에서 새 버전의 Task를 실행합니다. 새 Task가 Health Check를 통과한 뒤 기존 Task를 종료하므로 Backend 전체가 동시에 중단되지 않습니다. 검색·추천 사용자가 탐색을 계속하고, 장바구니와 결제 사용자가 배포 때문에 API 오류를 받지 않도록 하기 위한 설정입니다.
주문·결제 요청이 진행 중인 동안 기존 Task를 즉시 종료하지 않도록 ECS Service의 Rolling 배포 설정을 사용합니다. 로드밸런서의 Target 제외 지연 시간은 실제 배포 환경에서 필요한 유지 시간과 주문·결제 요청 특성을 확인한 뒤 설정합니다. 주문·결제 API는 네트워크 오류나 Task 교체 후 재시도될 수 있으므로 멱등성 키를 사용해 같은 주문이 중복 생성되지 않도록 합니다.
7.5. 장애 시 서비스 우선순위
처리 용량이 줄어든 상황에서는 주문·결제와 로그인 요청을 우선 처리합니다. 결제는 매출과 직접 연결되고, 로그인이 막히면 기존 사용자의 모든 기능이 중단되기 때문입니다. 검색·도서 상세와 리뷰 조회는 응답시간이 증가하더라도 계속 제공하고, AI 추천과 이미지 인식처럼 외부 처리시간이 긴 기능은 일시적으로 요청을 제한할 수 있습니다.
이를 통해 App Task나 EC2 장애가 발생하더라도 전체 기능을 동시에 중단하지 않고, 사용자의 구매 흐름과 핵심 계정 기능을 우선 유지합니다. 장애가 장기화되면 제한된 기능과 복구 상태를 사용자에게 안내해 반복 요청이 장애를 더 키우지 않도록 합니다.
7.6. 장애 감지와 복구 절차
장애 대응은 감지 → 트래픽 제외 → 대체 실행 단위 시작 → 정상 여부 확인 순서로 수행합니다.
| 장애 상황 | 감지 기준 | 자동 조치 | 서비스 영향 |
|---|---|---|---|
| Backend Task 중단 | 로드밸런서 Health Check 실패, ECS Task STOPPED | Target 제외 후 ECS Task 재실행 | 정상 Task가 요청 처리 |
| EC2 장애 | EC2 Status Check 실패, 인스턴스 연결 끊김 | ASG가 인스턴스 교체, ECS가 Task 재배치 | 해당 EC2의 Task만 영향 |
| AZ 장애 | 해당 AZ Target·EC2 다수 비정상 | 로드밸런서가 정상 AZ로 전달, ASG가 정상 AZ 확장 | 처리 용량 감소 가능 |
| 배포 오류 | 새 Task Health Check 실패 | 기존 Task 유지, 새 버전 배포 중단 | 기존 버전으로 서비스 유지 |
복구가 완료되기 전에는 정상 Target 수와 RequestCountPerTarget, 오류율, P95 응답시간을 확인합니다. 정상 Target이 부족해 평상시 Peak 625 RPS를 처리하지 못하면 주문·결제와 로그인 요청을 우선 유지하고, AI 추천·이미지 인식 요청을 제한해 핵심 기능의 처리 용량을 확보합니다.
8. 현재 설계의 한계
V2에서는 App과 AI를 별도의 ECS Service로 분리하고, ECS on EC2와 Capacity Provider를 사용해 Task와 EC2 용량을 관리합니다. 이를 통해 V1의 단일 서버 장애와 App·AI 간 자원 간섭 문제를 줄일 수 있습니다.
그러나 현재 구조에는 다음과 같은 한계가 있습니다.
8.1. ECS와 EC2 용량을 함께 관리해야 하는 문제
ECS Service는 Task 수를 관리하고 Auto Scaling Group은 EC2 수를 관리합니다. 따라서 Task를 확장할 때 실행 설정의 CPU·메모리 예약량, EC2의 남은 자원, Capacity Provider 상태를 함께 확인해야 합니다. EC2 용량이 부족하면 Task가 즉시 실행되지 않고 PENDING 상태에 머무를 수 있습니다.
8.2. 서비스별 설정 관리가 증가하는 문제
App과 AI를 별도 Service로 운영하면 실행 설정, CPU·메모리 예약량, Min·Desired·Max Task 수, 자동 확장 정책, 상태 확인, 배치전략을 Service별로 관리해야 합니다. 검색·추천·챗봇·배치 작업이 추가되면 관리해야 할 설정도 함께 증가합니다.
8.3. EC2 장애와 Task 복구 사이의 시간 차이
EC2에 장애가 발생하면 해당 EC2의 Task도 함께 중단됩니다. ECS가 Task를 다시 실행하려면 ASG가 EC2를 교체하고, 새 EC2가 ECS Cluster에 등록된 뒤 Task가 배치되어야 합니다. 따라서 다른 AZ의 Task가 요청을 처리할 수는 있지만 장애 AZ의 처리 용량이 즉시 복구되는 것은 아닙니다.
8.4. App과 AI의 확장 기준이 다른 문제
App은 요청 수, CPU·메모리 사용률, P95 응답시간을 기준으로 확장할 수 있습니다. 반면 AI는 임베딩 모델 메모리, 외부 LLM API 응답시간, 진행 중인 요청 수, AI PostgreSQL 연결 수가 중요한 지표입니다. 따라서 App과 AI에 동일한 자동 확장 기준을 적용하기 어렵습니다.
8.5. 배치와 자원 활용의 한계
Task를 AZ와 EC2에 분산하면 장애 영향은 줄어들지만 EC2별 남은 자원이 균등하지 않을 수 있습니다. 또한 distinctInstance 제약을 적용하면 실행 가능한 EC2가 부족할 때 Task가 PENDING 상태로 남을 수 있습니다. 따라서 가용성 확보와 EC2 비용 절감 사이에 균형이 필요합니다.