1 2 기존 인프라 한계 - 100-hours-a-week/KTB4-13th-wiki GitHub Wiki
1. 기존 인프라의 한계
V1은 초기 가입자 약 900명과 Peak Traffic 0.18 RPS를 적은 비용으로 처리하기 위해 App EC2와 AI EC2를 각각 한 대씩 운영했습니다. 트래픽이 적었기 때문에 짧은 장애와 수동 운영을 감수할 수 있었습니다.
V2에서는 7년 차 누적 가입자 250만 명, MAU 100만 명, 평균 DAU 10만 명, 평상시 Peak Traffic 625 RPS까지 증가합니다. 기능 추가로 세션당 백엔드 요청도 최대 12회에서 약 15회로 늘어납니다. 캠페인과 순간적인 집중 유입에 대비한 인프라 검증 기준은 평상시 Peak의 2배인 1,250 RPS로 설정합니다.
V1은 이러한 규모의 사용자와 요청량을 고려하지 않은 초기 구조입니다. 따라서 사용자 피해가 크고 복구하기 어려운 문제부터 검토합니다.
1.1. 검토 우선순위
| 순위 | 항목 | 우선 검토하는 이유 |
|---|---|---|
| 1 | 데이터 일관성·무결성 | 주문·결제·회원 데이터가 누락되거나 중복되면 금전적 피해가 발생하며 사후 복구도 어렵습니다. |
| 2 | 가용성·복구성 | App EC2와 MySQL이 함께 중단되면 정적 화면을 제외한 대부분의 기능을 이용할 수 없습니다. |
| 3 | 응답 성능 | 전체 요청의 약 83%가 홈·검색·도서 상세 등의 조회 요청이므로 지연이 사용자 경험에 직접 영향을 줍니다. |
| 4 | 확장성 | 단일 EC2의 자원이 전체 처리량의 상한이며 Backend와 MySQL을 필요한 만큼 따로 늘리기 어렵습니다. |
| 5 | 운영 일관성·자동화 | 서버가 늘어날수록 배포·설정·상태 확인과 장애 복구 대상도 함께 증가합니다. |
| 6 | 관측 가능성 | 장애와 지연이 발생한 위치를 확인해야 빠르게 복구하고 확장할 대상을 판단할 수 있습니다. |
| 7 | 보안성 | 회원·배송·주문정보와 외부 API 비밀정보를 보호해야 하며 서버가 늘어나면 권한 관리 대상도 증가합니다. |
| 8 | 비용 효율성 | 이중화와 자동 확장은 운영비를 늘리므로 확보되는 안정성과 추가 비용을 함께 비교해야 합니다. |
주문·결제 데이터의 정확한 보존을 가장 우선합니다. 그다음 장애 중에도 서비스를 유지할 수 있는지, 트래픽이 증가해도 응답 성능과 처리 용량을 유지할 수 있는지 검토합니다.
서버가 늘어날 때 발생하는 운영·관측·보안 문제도 확인하고, 각 해결 방법의 비용을 함께 비교합니다.
1.2. 예상되는 문제
1. 데이터 일관성·무결성
현재 MySQL의 주문 데이터와 S3의 장기 보관 거래기록은 별도로 저장됩니다. 두 작업 중 하나만 성공하면 주문 데이터와 보관 기록이 서로 달라질 수 있습니다.
요청이 재시도되면 같은 주문이나 결제가 중복 처리될 가능성도 있습니다. Backend를 여러 대로 늘릴 때 세션이나 파일을 서버 내부에 저장하면 요청이 전달된 서버에 따라 사용자 상태가 달라질 수 있습니다.
애플리케이션과 DB 스키마를 함께 변경한 뒤 Backend만 이전 버전으로 되돌리면 DB 구조와 호환되지 않을 수 있습니다.
2. 가용성·복구성
Backend와 MySQL은 하나의 App EC2에서 함께 실행됩니다. App EC2에 장애가 발생하면 로그인·검색·장바구니·주문·결제가 모두 중단됩니다.
Docker 재시작 정책은 종료된 컨테이너를 다시 실행할 수 있지만 EC2 자체의 장애에는 대응하지 못합니다.
Recreate 배포 중에도 요청을 대신 처리할 Backend가 없어 전체 API가 일시적으로 중단됩니다.
EC2가 복구되더라도 Backend와 MySQL의 실행 상태와 데이터 이상 여부를 확인해야 합니다.
현재는 요청을 대신 처리할 App 서버와 자동으로 전환할 DB가 없어 복구가 완료될 때까지 서비스를 제공하기 어렵습니다.
초기 사용자 900명 규모에서는 짧은 중단을 감수할 수 있었지만, 누적 가입자 250만 명과 MAU 100만 명 규모에서는 같은 시간의 장애도 훨씬 많은 사용자의 주문과 서비스 이용 실패로 이어집니다. 월 예상 매출 1억 5천만 원을 균등하게 환산하면 DB 전체 중단 1분당 직접 매출 손실은 약 3,472원입니다.
따라서 App은 여러 인스턴스와 Load Balancer로 구성하고, 운영 DB는 다른 AZ의 Standby로 자동 전환할 수 있는 RDS MySQL Multi-AZ 구성을 기본안으로 사용합니다.
3. 응답 성능
Backend와 MySQL은 같은 t3.small의 CPU·메모리·디스크를 공유합니다.
조회 요청이 늘어나면 MySQL의 연결과 디스크 I/O가 증가하여 Backend가 사용할 수 있는 자원이 줄어들 수 있습니다. Backend 부하가 증가하면 MySQL의 처리 성능도 영향을 받습니다.
전체 요청의 약 83%는 홈·검색·도서 상세 등의 조회 요청입니다. 도서를 탐색하는 동안 여러 API를 연속해서 호출하므로 일부 API의 지연이 전체 검색과 구매 경험을 느리게 만들 수 있습니다.
외부 AI API의 응답이 늦어지면 Backend의 연결과 처리 자원이 오래 점유됩니다. 이 상태에서 요청이 계속 들어오면 일반 조회와 주문·결제 요청에도 영향을 줄 수 있습니다.
평상시 Peak 625 RPS에서 백엔드 요청 1건당 평균 4개의 DB Query가 실행된다는 임시 가정을 적용하면 운영 계획값은 약 2,500 QPS입니다. 검증 Peak 1,250 RPS에서는 약 5,000 QPS입니다. 이 값은 실측값이 아니므로 API별 SQL 실행 횟수, Query Latency와 Slow Query를 측정해 보정해야 합니다.
4. 확장성
현재는 App EC2 한 대의 CPU와 메모리가 Backend 처리량의 상한입니다. EC2 사양을 높여 처리 용량을 늘릴 수는 있지만 단일 서버에 의존하는 문제는 그대로 남습니다.
App EC2를 그대로 복제하는 것만으로는 확장할 수 없습니다.
여러 App 서버로 요청을 분산할 구조가 없고, 서버마다 MySQL을 함께 실행하면 데이터도 자동으로 공유되지 않기 때문입니다.
Backend와 MySQL이 같은 EC2에 결합되어 있어 부하가 발생한 부분만 따로 확장하기 어렵습니다. 서버 수도 고정되어 있어 평상시와 집중 유입 시간의 트래픽 차이에 맞춰 처리 용량을 조절할 수 없습니다.
평상시 625 RPS와 검증 기준 1,250 RPS를 처리하려면 Backend를 Stateless하게 구성하고 Load Balancer와 Auto Scaling을 통해 여러 인스턴스로 수평 확장해야 합니다. DB는 App에서 분리하여 모든 App 인스턴스가 동일한 중앙 데이터 저장소를 사용해야 합니다.
5. 운영 일관성·자동화
V1은 각 EC2에서 Docker Compose를 실행하고 정해진 서버를 대상으로 배포합니다. 서버가 늘어나면 배포·설정·상태 확인과 장애 복구 대상도 함께 증가합니다.
서버를 개별적으로 관리하면 이미지 버전과 환경변수가 달라질 수 있습니다. 일부 서버에서 배포가 실패하거나 누락되면 서로 다른 버전의 Backend가 동시에 실행될 수도 있습니다.
Docker 재시작 정책은 종료된 컨테이너를 다시 실행하지만 EC2 장애 시 같은 환경의 서버를 생성하거나 다른 서버에 컨테이너를 배치하지는 않습니다.
컨테이너를 실행하기 위해 EC2를 계속 추가하면 서버별 OS와 유휴 자원도 늘어납니다.
개발자 6명 중 인프라 담당자 2명도 개발을 병행하므로 서버 증가에 맞춰 수동 운영 업무를 늘릴 수 없습니다. 배포, 설정, 상태 확인, 확장과 장애 복구를 자동화해야 합니다.
6. 관측 가능성
현재 Backend와 MySQL은 같은 EC2 자원을 사용합니다.
CPU나 디스크 사용량이 증가해도 어느 구성요소에서 문제가 발생했는지 바로 구분하기 어렵습니다.
추천 기능의 지연도 Backend·네트워크·외부 AI API 중 어느 구간이 원인인지 확인해야 합니다.
초기에는 사용자의 오류 제보를 받은 뒤 서버 로그를 직접 확인할 수 있었습니다.
그러나 MAU 100만 명 규모에서는 일부 요청에서만 발생하거나 짧은 시간 반복되는 지연과 오류를 수동으로 찾기 어렵습니다.
장애를 늦게 발견하면 복구도 늦어집니다. 병목을 구분하지 못하면 어떤 계층을 확장해야 하는지도 판단하기 어렵습니다.
따라서 API 응답시간·오류율, 서버 자원, DB 연결·IOPS와 외부 API의 지연·실패·호출량을 구분하여 확인할 수 있어야 합니다. 평상시 625 RPS와 검증 1,250 RPS에서 P95·P99 응답시간과 오류율을 함께 측정해야 합니다.
7. 보안성
Backend와 MySQL이 같은 EC2에 있으므로 App 서버의 접근정보나 취약점이 노출되면 DB까지 피해가 이어질 수 있습니다.
북적북적은 카카오 로그인 정보와 이름·주소·전화번호 등의 배송정보를 처리합니다.
외부 AI API도 사용하므로 DB 비밀번호와 API Key뿐 아니라 외부로 전달되는 사용자 입력도 보호해야 합니다.
서버가 늘어나면 네트워크 경로와 접근 권한, 비밀정보를 관리할 대상도 증가합니다. 서버별 설정이 달라지면 필요하지 않은 포트나 권한이 노출될 가능성도 커집니다.
App과 DB를 분리한 뒤 DB는 Private Subnet에 배치하고 App Security Group에서만 접근하도록 제한해야 합니다. 저장 데이터 암호화와 TLS를 적용하고 비밀정보는 중앙에서 관리해야 합니다.
8. 비용 효율성
가용성과 확장성을 확보하기 위해 서버를 단순히 추가하면 트래픽과 관계없이 고정비가 증가합니다.
Peak Traffic을 기준으로 모든 서버를 계속 실행하면 평상시에는 사용하지 않는 자원에도 비용을 지불하게 됩니다.
컨테이너마다 EC2를 별도로 배정하면 각 서버의 OS와 유휴 CPU·메모리가 반복됩니다. 반대로 서버 수를 지나치게 줄이면 장애나 집중 유입이 발생했을 때 처리 용량이 부족할 수 있습니다.
Load Balancer와 다중 AZ, 관리형 데이터베이스에도 별도 비용이 발생합니다. 자동 확장 기능 자체에는 별도 요금이 없지만 확장으로 추가된 서버·디스크·모니터링 사용량에는 요금이 발생합니다.
월 예상 매출 1억 5천만 원 규모에서는 서비스 중단과 주문·결제 데이터 손실의 영향이 기존보다 큽니다. 따라서 인프라 비용만 최소화하기보다 장애 손실, 수동 운영 인력, 복구 목표와 CSP 이전 비용을 포함한 총소유비용으로 비교해야 합니다.
다음 단계에서는 각 문제가 V1 구조의 어떤 부분에서 발생하는지 한계 지점을 정리하고, 가능한 해결 방법과 비용을 비교합니다.
2. 기존 인프라 구조의 한계와 개선 방향
V1 구조의 한계를 App 서버, 요청 분산 구조, 데이터베이스, AI 연동 구조로 나누어 검토합니다.
2.1. 단일 App 서버
단일 App 서버의 장애와 확장 문제를 해결하는 방법을 정리합니다.
2.2. 요청 분산 구조
여러 App 서버에 요청을 분산하고 비정상 서버를 제외하는 방법을 정리합니다.
2.3. 데이터베이스
MySQL을 App 서버에서 분리하고 데이터 보호와 복구 방식을 개선하는 방법을 정리합니다.
2.4. AI 연동 구조
AI Server·Vector DB·외부 LLM API를 Backend와 안정적으로 연결하는 방법을 정리합니다.