v2 상황과 고려사항 설정 - 100-hours-a-week/KTB4-5th-wiki GitHub Wiki

4단계. 컨테이너 기반 서비스 확장 및 운영 자동화 설계

상황 가정

  • 서비스를 지속적으로 개발 및 운영을 하면서 규모가 급속도로 커짐. 규모가 커지다보니 빠르게 기술을 개발하여 바로 적용하는 것보다는 한번 검증하며 적용하는 등 안정성과 확장성이 중요해짐.
  • 이전에 중요시 여긴 가치: 신속성, 간편성, 비용 절감
  • 현재 중요한 가치: 안정성, 가용성, 확장성, 보안성

구체적인 가정

  • 고려 사항
    • MAU
    • 동시 접속자 수 (Concurrency)
    • RPS, Peak RPS
    • 읽기 쓰기 비율
    • Latency
    • 에러율 (SLO,SLA,SLI)
    • 가용성 (MTBF,MTTR)
    • 확장성
    • 서비스의 트래픽 특성

1. MAU

2. Peak 동시 접속자 수 (Concurrency)

  • 추정 방식: MAU → DAU(스티키니스 비율) → Peak 동시접속자(CCU) 순서로 계산
  • DAU/MAU 스티키니스 = 50% 가정 — 다먹자는 냉장고·식사라는 매일의 생활에 밀착된 서비스라는 판단
    • 카테고리별 벤치마크 비교(2026년, vmobify "DAU/MAU Stickiness Benchmarks by Category"): 메시징/소셜 커뮤니케이션 50%, 소셜·콘텐츠 피드 40~60%, 게임 20~50%, 핀테크/뱅킹·B2B SaaS 10~25% 전체 앱 평균 약 20% (https://vmobify.com/blog/dau-mau-stickiness-benchmarks)
    • DAU ≈ 230,000 × 50% ≈ 115,000명
  • 단순화를 위해 피크 시간대 집중 비율을 별도로 두지 않고, 피크 시간대에는 DAU 전체가 접속한다고 가정 → 피크 세션 = 115,000세션/시간
  • Little's Law: CCU = (피크 세션 수 × 평균 세션 지속시간(분)) ÷ 60. 평균 세션 5분 가정 → CCU ≈ (115,000×5)÷60 ≈ 9,583.3명
  • 안전 마진 20~30% 적용 → 설계 목표 피크 CCU ≈ 11,500명
  • 실사용 데이터 없이 잡은 가정치이므로 출시 후 실제 로그 기반 재검증 필요

3. RPS, Peak RPS

  • 공식: RPS = DAU × 세션당 요청 수 ÷ 윈도우(초)

    • DAU = 115,000명(2번 항목), 세션당 요청 수 = 3회, 알림 버스트 윈도우 = 5분(300초), 식사시간 윈도우 = 1시간(3600초)
  • 평시 RPS: 식사시간 1시간 집중 기준 115,000×3÷3,600 ≈ 96 RPS → ASG 최소 용량(min capacity) 기준

  • Peak RPS: DAU 전체가 알림 발송 5분 안에 접속한다는 극단 가정 → 115,000×3÷300 = 1,150 RPS → ASG 최대 용량(max capacity) 기준, Auto Scaling으로 대응

  • → 설계 목표 Peak RPS = 1,150 RPS 유지 (DAU 윈도우 기반). Little's Law 크로스체크가 훨씬 큰 값(11,500)을 제시하므로, 더 보수적으로 가고 싶다면 이 값까지 상향하는 것도 검토 가능 — 다만 이 경우 서버 대수·비용이 10배 가까이 늘어나므로 팀 논의 필요

  • 전제조건: 1,150 RPS는 "DAU 전체가 5분 안에 몰린다"는 극단 가정이므로, 알림을 배치로 나눠 분산 발송하는 것이 이 목표를 안전하게 유지하는 전제 조건

4. 읽기 쓰기 비율

  • 근거(개인 경험 기반): 주말에 한 번 장을 보고 그 재료로 한 주를 생활하는 패턴을 일반화 — 쓰기(재료 등록)는 장보기 직후 주 1회 몰리는 버스트성 이벤트, 읽기(오늘 뭘 요리할지 확인)는 재료가 떨어질 때까지 매일, 하루 여러 번 반복
  • 가정: 쓰기 세션 1회/주 vs 읽기 세션 7~14회/주(하루 1~2회) → 읽기:쓰기 ≈ 7:1 ~ 14:1
  • 트레이드오프: 읽기 비중이 압도적이므로 DB Read Replica 우선순위가 높음. 캐시(Redis 등)도 반복 조회 결과에 효과적 — Read Replica는 일관성 유지가 쉽지만 비용↑, 캐시는 응답속도는 빠르지만 무효화 로직 복잡도고 상승함.

5. Latency

  • 근거 (둘 다 Google 공식 문서 web.dev 기준):
    • INP(Interaction to Next Paint, Core Web Vitals): "Good" 기준 = 200ms 이하. 이상적으로는 100ms가 이론적 최적치이지만, 실사용 데이터(CrUX) 기준 100ms는 모바일 기기의 12%만 달성 가능한 반면 200ms는 모바일 56%/데스크톱 96%가 달성 가능해, 현실적으로 도달 가능하면서 좋은 사용감을 주는 기준으로 200ms를 채택함 (https://web.dev/articles/defining-core-web-vitals-thresholds)
    • RAIL 성능 모델: "100~1000ms 구간은 작업의 자연스러운 흐름으로 느껴지는 범위이며, 1000ms(1초)를 넘어서면 사용자가 작업에 대한 집중력을 잃기 시작한다(Beyond 1000 milliseconds (1 second), users lose focus on the task)" (https://web.dev/articles/rail)
  • 목표(SLO):
    • 목표(Good): API 응답시간(p50) 200ms 이하 → Google이 정의한 "좋음" 사용감 기준(INP Good)
    • 마지노선(Hard limit): p95/p99 기준 1000ms(1초) 이하 → RAIL 모델상 사용자가 집중력을 잃기 시작하는 경계. 1000ms 초과 요청은 SLO 위반으로 간주해 알림/모니터링 대상으로 설정
    • 일단 마지노선부터 달성하고 최적화를 하면서 목표에 가까워지도록 할 계획임.
  • AI 추천 API는 모델 추론 특성상 200ms/1000ms 기준을 적용할 수 없음. — 로딩 UI·비동기 처리(추천 결과 스트리밍, "준비 중" 상태 표시 등)로 체감 지연을 완화하는 방향으로 계획함.
  • 트레이드오프: 200ms를 목표로 타이트하게 잡을수록 캐싱·CDN·서버 스펙 상향 등 비용이 늘어남.

6. 에러율 (SLO, SLA, SLI)

  • 에러율은 기존 운영 데이터가 쌓여야 명확하게 설정 가능한 영역이라, 지금은 간단하게 설계함
  • SLI 예시: HTTP 5xx 비율, 성공 요청 비율, 헬스체크 성공률
  • SLO 예시: 30일 기준 요청 성공률 99.9% 이상(에러율 0.1% 이하)
  • SLA: 현재는 내부 서비스이므로 대외 SLA는 불필요, 추후 B2B 제휴·외부 API 제공 시 도입 검토

7. 가용성 (MTBF, MTTR)

  • 가용성도 기존 운영 데이터가 쌓여야 명확하게 설정 가능한 영역이라, 지금은 간단하게 설계함
  • 목표 가용성 예시: 99.9%(월 다운타임 약 43분 이내)
  • MTTR 단축: v1에서 설계한 Health Check + Rollback 자동화(3단계 CD 문서 참고)를 확장해 장애 감지~복구 시간 최소화
  • MTBF 향상: v1의 단일 EC2(SPOF) 구조에서 벗어나 Multi-AZ + Auto Scaling Group으로 이중화 필요

8. 확장성

  • v1(Docker Compose 단일 EC2) 구조에서 오토스케일링이 가능한 구조로 전환 필요
  • 후보 방향(트레이드오프 비교, 최종 선택은 팀 논의 필요):
    • EC2 + Auto Scaling Group + ALB: 기존 Docker 기반 구조를 크게 바꾸지 않고 확장 가능. 다만 인스턴스 관리·배포 자동화를 직접 운영해야 하는 부담
    • ECS(Fargate 또는 EC2 launch type): 컨테이너 오케스트레이션을 AWS가 관리해 운영 부담↓, 다만 AWS 종속성↑ 및 학습 비용 발생
    • EKS(Kubernetes): 가장 유연하고 생태계가 넓지만 러닝커브·운영 복잡도가 가장 높아 소규모 팀에는 과잉일 수 있음
  • DB 확장성: RDS로 전환 + Read Replica 도입 검토 (v1은 EC2에 직접 MySQL을 구동 중)

9. 서비스의 트래픽 특성 (앞선 항목의 정리)

  • 일간 피크: 저녁 요리 준비 시간대(18~19시)에 트래픽 집중 (2번 동시 접속자 수 항목의 피크 시간대 가정)
  • 이벤트성 스파이크: 유통기한 임박 알림(Push) 발송 직후 5분 안에 DAU가 몰리는 급증 구간 (3번 RPS 항목의 Peak RPS 산정 근거)
  • 주간 패턴: 쓰기(재료 등록)는 주말 장보기 직후 주 1회 몰리는 버스트, 읽기(냉장고 확인·레시피 조회)는 매일 반복 (4번 읽기 쓰기 비율 항목)
  • 종합: 다먹자의 트래픽은 예측 가능한 특정 시각(알림 발송 시각, 저녁 시간대, 주말)에 집중되는 스파이크형 패턴을 가짐
  • 트레이드오프: 예측 가능한 피크(저녁 시간대, 알림 발송 시각)는 스케줄 기반 사전 스케일링(Scheduled Scaling)으로 대응 가능(구현 단순, 예측 정확도 필요) vs 그 외 돌발 스파이크는 반응형 오토스케일링(Target Tracking) 필요(유연하지만 반응 지연 존재) — 두 전략을 함께 쓰는 것을 검토 (3번 항목의 결론과 연결)