기존 볼륨 앵커가 실측과 어긋나 예산을 다시 세웠다. 결론부터: 확정 설정으로 활성 1M DAU가 월 $488 — 순진 구현 대비 −93%, 원 예산 $1,350의 36%다.
§0 결론 · §1 비용 계산기 · §2 근거(실측 대사) · §3 확정 파라미터 · §4 절감 레버와 리스크 · §5 아키텍처 · §6 부록
| 항목 | 값 | 성격 |
|---|---|---|
| 볼륨 기준선 | 명령어 실행 수 | 플랫폼 원시 발화 아님 — 비명령 ~45% 제외 (D11) |
| 콜당 레이크 이벤트 배수 | 3 | 확정 |
| L1 DAU dedup | on | 무위험 — 볼륨 −33%, 지표 정합성은 오히려 개선 (D7) |
game_event_bundle_max (n) | 30 | 수익 체감 지점 — 메시지 24KB(한도의 2.3%) (D10) |
game_event_bundle_flush_ms | 200 | 유일한 리스크 노브 — 유실 창 = 이 값. 인스턴스당 처리율 실측 후 조정(V-3) |
| 평균 줄 크기 | ≤1KB (목표 0.5KB) | 소급 불가 구현 전 확정 (D6) |
| 레이크 raw 보존 | 7일 (3~30 조정 가능) | 저장비 저렴 — 3→30일 폭 월 +$52 (D5) |
| ev / 활성DAU | 587 | L1 적용 기준 (D9) |
| Lambda 배치 | non-VPC | 데이터 전송 $0 · NAT(월 ~$87) 회피 — 근거는 §6 |
n=30 · flush_ms=200events: [] 확정 — 소급 불가flush_ms 조정 — 인스턴스당 콜 처리율 실측 후 확정(V-3). 유실 창이 곧 이 값표기 — 본 문서의 "발화"는 명령어 실행(게임 명령 호출)을 가리킨다. 플랫폼 원시 발화량(비명령 포함, ~1.8배)과 구분한다.
기본값은 §0 확정 설정(활성 1M DAU · 배수 3 · L1 on · n=30)이며 §0의 $488을 재현한다. 슬라이더·숫자입력·프리셋으로 각 파라미터의 민감도를 직접 확인할 수 있다.
daily_active_user가 콜당 1회 → 유저·일당 1회로 붕괴. 실효 절감 ~33%game_event_bundle_max — 기본 30(수익 체감 지점). 요청 합산 1 MiB 상한으로 자동 클램프| 항목 | 산식 | 월액 |
|---|
단가(Seoul, PRD 검증값): SQS $0.40/백만 req(10건 배치) · Lambda 앵커 $550/월@3억 ev/day 선형 · S3 $0.025/GB-월(압축 1/6) · Athena $5/TB(D-1+D-2 일 1회, Parquet 스캔 1/10) · CW 참고치 $0.76/GB ingest. SQS 수신·삭제와 S3 PUT까지 명시 행으로 분리 — 앵커(3억 ev/day·0.8KB)에서 소계 ≈ $1,140 × 마진 1.15 ≈ $1,310으로 PRD prod 앵커($1.3~1.5K)와 정합.
운영 지표 실측(단일 봇, 약 5개월)으로 기존 비용 모델의 가정을 대사했다. 아래는 절대 수치가 아니라 검증 결과와 방법론이다 — 원 데이터는 비공개.
| 모델 요소 | 기존 가정 | 실측 판정 |
|---|---|---|
| 활성률 | DAU의 15~20% | 유효 — 실측도 15~25% |
| 인당 명령어 수 | 15콜 | 수십 배 과소 — 게임 특성상 훨씬 높음 |
| 콜당 레이크 이벤트 | 35 (5×7) | 서술 오류 — 실제 3 |
| 상한 앵커 단위 | "1M DAU" 기준 | 정의 혼동 — 그 볼륨은 누적 이용자에 대응, 활성이 아니었음 |
| 명령 분포 | 고르게 분포 → 선별 절감 불가 | 반증 — 소수 명령이 볼륨 대부분 차지 |
플랫폼 원시 발화량(잡담·오타 포함)과 실제 게임 명령 실행 사이에는 큰 차이가 있다(원시 발화가 명령 실행의 약 1.8배). 레이크 대상은 후자다.
키 설계가 판정 근거다: <bot>:user:{uid}:dau:{YYYY-MM-DD}(KST) — 유저·일당 1건이지 콜당 1건이 아니다. 그런데 daily_active_user는 콜마다 발행되므로, L1은 이 성분을 콜 수에서 유저 수로 붕괴시킨다.
| 구분 | 산식 | 활성 1M DAU/일 |
|---|---|---|
| L1 미적용 | 콜 × 3 | 8.8억 |
| L1 적용 | 콜 × 2 + 활성 유저 1건 | 5.87억 |
기존 "비용 효과 ~3%"는 1/35에서 나온 값으로, 배수 오류의 파생값이다. 실제 배수가 3이므로 1/3이 맞다. L1은 정합성 도구가 아니라 2순위 비용 레버다.
n은 "메시지 개수"가 아니라 "메시지 안의 이벤트 개수"다. 메시지 수는 AWS 하드 한도로 항상 10개다.
flowchart LR
R["SendMessageBatch 요청 1회
합산 ≤ 1 MiB"] --> M["메시지 10개
(하드 한도, 조정 불가)"]
M --> E["각 메시지 body에
이벤트 n개 — 조정 대상"]
E --> T["요청당 총 이벤트 = 10 × n"]
| 한도 항목 | 값 | 성격 |
|---|---|---|
| 요청당 메시지(entry) 수 | 10 | 하드 (TooManyEntriesInBatchRequest) |
| 개별 메시지 크기 | 1 MiB | 하드 |
| 요청 합산 페이로드 | 1 MiB | 10개를 채우면 이쪽이 먼저 걸린다 (BatchRequestTooLong) |
⇒ n_max = floor(1,000,000 / (10 × 줄크기)) — 0.5KB에서 200 · 0.8KB에서 125 · 1.0KB에서 100. 계산기의 최대(n_max) 버튼이 현재 줄 크기 기준으로 자동 계산한다.
| n | 요청당 ev | 메시지 크기 | 1M 활성 | SQS 비중 |
|---|---|---|---|---|
| 1 | 10 | 24 KB | $2,837 | 86% |
| 3 | 30 | 2.4 KB | $1,217 | 67% |
| 10 | 100 | 8 KB | $650 | 37% |
| 30 | 300 | 24 KB | $488 | 17% |
| 125 | 1,250 | 100 KB | $426 | 5% |
n=30이 수익 체감 지점이다 — 여기서 SQS가 17%로 떨어져 Lambda에 최대 항목 자리를 넘겨주고, n=125까지 올려도 $62밖에 더 못 줄인다. 메시지 크기는 24KB로 1 MiB 한도의 2.3%에 불과해 여유가 크다.
| 단계 | 설정 | 월액 | 직전 대비 |
|---|---|---|---|
| 0 | 순진 구현 (콜 단위 발행 · n=1 · L1 off) | $7,061 | — |
| 1 | + 요청 배칭 (10 entries/req) | $4,230 | −40% |
| 2 | + L1 dedup on | $2,837 | −33% |
| 3 | + 묶음 n=30 확정 기본값 | $488 | −83% |
| 4 | + 줄 크기 0.5KB | $354 | −27% |
| 5 | + n=200 (0.5KB의 n_max) | $285 | −19% |
| — | (보존 3↔30일 폭 / 강화 축약) | ±$61 / −$342 | ±11% / −48% |
| 레버 | 절감 | 리스크 | 되돌리기 |
|---|---|---|---|
| L1 dedup | −33% | 없음 — 지표 정합성은 오히려 개선 | 플래그 off |
| 묶음 n=30 | −83% | 없음 — 버퍼는 이미 전제. 늘어나는 건 메시지 크기뿐(24KB) | 설정값 |
flush_ms = 200 | (구조적 필수) | 유실 창 200ms — 프로세스 강제 종료 시 버퍼 잔량. 기존 fire-and-forget 유실과 동일 계열 | 설정값 |
| 줄 크기 0.5KB | −27% | 소급 불가 — 삭제 필드 영구 복구 불가 | ❌ |
| 보존일 (3~30) | ±11% | 저장비 저렴 — 단축 실익 없음, 여유 시 늘려 디버깅 창 확보 | 삭제분 복구 불가 |
| 강화 축약 | −48%+ | 소급 불가 + 지표 해상도 영구 상실 | ❌ |
flowchart TB
subgraph BOTS["n개 봇 (수평 확장 — 파이프라인 무변경)"]
B1["봇 A"]
B2["봇 #2"]
BN["봇 #n"]
end
LG["log_game_event() — 봇 중립 훅
payload 확정 직후 · 줄 크기 ≤1KB"]
B1 --> LG
B2 --> LG
BN --> LG
LG --> PUB["SQS 배치 발행 (기존 idiom 재사용)
events:[] × n · SendMessageBatch 10건"]
PUB --> Q["SQS game-events 큐 (신규)
standard + DLQ"]
Q --> LAM["소비자 Lambda (신규, Go/arm64)
flat-map → Parquet"]
LAM --> LAKE["S3 레이크 (SSOT)
Parquet · Glue projection"]
LAKE --> AGG["일별 집계 배치 KST 03:00
daily_* 영구 보존 · 실패 알람 필수"]
AGG --> ADMIN["admin 대시보드"]
LAKE -.->|"raw 7일 롤링 삭제"| DEL[("저장비 상수화")]
CW-경유가 요구하던 전용 Firehose·Dynamic Partitioning·normalizer·구독필터는 전부 불필요하다. bot_code는 파티션이 아니라 컬럼이라 봇 추가 시 DDL·Lambda 무변경.
| # | 결정 | 현재 상태 |
|---|---|---|
| D1 | 아키텍처 | 단일 SQS 배치 티어 — CW-경유 폐기. qa가 prod 경로를 그대로 검증 |
| D2 | 발행·소비자 | 기존 SQS 경로 재사용 + Go/arm64 Lambda(workers-go idiom 재사용, parquet-go) |
| D3 | 소멸 리스크 | 구독필터 한도·prod 로그레벨·이중 적재·whitelist 소급 불가 — CW 고유 리스크 4건 소멸 |
| D4 | 예산 재확정 | 활성 1M DAU $488/월(L1+n=30). 앵커 단위는 활성 DAU |
| D5 | 보존 | raw 7일 기본 · 3~30일 조정 가능(3→30일 월 +$52) + 집계 영구 · 집계 실패 알람 필수 |
| D6 | 스키마 게이트 | 소급 불가 평균 줄 크기 ≤1KB, 목표 0.5KB |
| D7 | L1 dedup 격상 | 실효 33.2% — 정합성 전용이 아니라 2순위 비용 레버 |
| D8 | 수용 트레이드오프 | Logs Insights 실시간 조회 상실(Athena 준실시간 보완) · 발행 유실은 기존 fire-and-forget과 동일 수준(DLQ + 레이크 대사) |
| D9 | 계수 재확정 | 587 ev/활성DAU(L1 적용) · 배수 3 · 콜/활성유저 293(피크)~378(평균) |
| D10 | 묶음 n 노브 | game_event_bundle_max 기본 30 · flush_ms 기본 200 · 물리 상한 125(0.8KB) · 수익 체감 지점 30 |
| D11 | 볼륨 기준선 신규 | 명령어 실행 수(플랫폼 원시 발화 아님) |
| 서비스 | 과금 항목 | 서울 실단가 | 비고 |
|---|---|---|---|
| SQS | standard 요청 (발행·수신·삭제 공통) | $0.40 / 백만 | 월 1,000억 req까지 Tier1 — 본 워크로드 전량 해당 |
| Lambda | 요청 / 컴퓨트 (arm64) | $0.20 / 백만 $0.0000133334 / GB-초 | x86 대비 −20% — 채택 완료 |
| S3 | PUT / Standard 저장 | $0.0045 / 1천 $0.025 / GB-월 | 첫 50TB 구간 |
| Athena | 스캔 | $5.00 / TB | Parquet 컬럼 프루닝으로 실스캔 축소 |
| 데이터 전송 | egress (동일 리전 · non-VPC) | $0 | 전 구간 같은 리전 AWS 서비스 간 통신 — 인터넷·리전 경계 없음 |
| CW Logs | ingest / 저장 (참고 — 기각 경로) | $0.76 / GB $0.0314 / GB-월 | CW-경유가 4~5배 비싸 기각된 근거 |
감각치: 이벤트 100만 건당 약 $4.5(n=1 기준). Glue Data Catalog는 partition projection이라 크롤러·ETL Job 과금이 없어 $0.
egress는 비용 모델에서 빠진 게 아니라 실제로 0이라 라인이 없다. 이 로그레이크 Lambda의 유일한 출력은 S3 PUT이고, 전 구간이 같은 리전(ap-northeast-2) AWS 서비스 간 통신이라 데이터 전송료가 발생하지 않는다. AWS는 동일 리전 S3 in-transfer(써 넣기)에 전송료를 부과하지 않으며, 과금은 인터넷 egress나 리전 경계 통과 시에만 일어난다 — 이 설계엔 둘 다 없다. 파이프라인의 유일한 종착지가 S3이므로 외부로 나가는 트래픽 자체가 존재하지 않는다.
| 구간 | 방향 | 데이터 전송 요금 |
|---|---|---|
| 봇(ECS) → SQS | send | 동일 리전 — $0 |
| SQS → Lambda | receive | 동일 리전 — $0 |
| Lambda → S3 | PUT | 동일 리전 S3 — $0 |
| Athena → S3 | scan | 동일 리전 — $0 |
Lambda를 VPC 밖에 두면 AWS 백본으로 S3 퍼블릭 엔드포인트에 바로 닿는다 — NAT 불필요, 전송료 0. 반대로 VPC 안에 넣었다면 S3 접근에 아래 둘 중 하나가 필요했다.
| 방식 | 월 비용 | 비고 |
|---|---|---|
| NAT Gateway | ~$32.85 + $0.045/GB | 활성 1M DAU(압축 ~40GB/일 = 월 1.2TB)면 처리료만 월 ~$54 추가 + 고정비 $33 |
| S3 Gateway VPC Endpoint | $0 | 게이트웨이형은 무료 — 단, VPC 구성·관리 부담은 남음 |
non-VPC 선택이 NAT 비용(월 ~$87)을 통째로 회피한다. Lambda 컴퓨트 라인($338)은 순수 GB-초라 전송 항목이 애초에 없다.
| # | 내용 | 닫는 시점 |
|---|---|---|
| V-1 | 게임 이벤트 ÷ 명령어 실행 ≈ 3 검증 — 초과 시 훅이 명령 인식 이전으로 샌 것 | qa 적재 +1주 |
| V-2 | 외부 API 호출 실측과 산출 볼륨의 갭 — 명령어 외 발행 경로 존재 여부 | V-1과 동시 |
| V-3 | flush_ms 확정 — 인스턴스당 콜 처리율 실측 후 200ms 적정성 판단(유실 창 = 이 값). 함께 n=30이 flush당 누적량을 1메시지로 덮는지 확인 | qa 부하 시험 |