← 프로젝트

회사AI 게임 스타트업2026.06 – 2026.09

인메모리 게임 엔진의 상태 외부화와 수평확장 설계

동접 한 자릿수에서 넘어지던 엔진의 OOM을 재현하고, 상태를 RDS·DynamoDB로 빼내 세 자릿수까지. 다음 단계는 9개 후보 아키텍처로 설계했다.

RAM 워킹셋 (상한 캡)
RDS PostgreSQL · append 영속화
DynamoDB · 런타임 상태
역할
백엔드 기술자문 · 감사와 리팩터링 설계 · 영속화 구현 · 인프라 아키텍트
기술
Node.js · TypeScript · PostgreSQL (RDS Multi-AZ) · DynamoDB · Redis · k6 · AWS (NLB · ALB · EC2 ASG · Fargate) · Terraform · Mermaid
170→1,554
12분 만에 불어난 기억 배열 (OOM 재현)
116
동시 활성 세션 피크, 무중단
120만 행
영속화 계층 운영 · 마이그레이션 43개
9안 · 5축
수평확장 후보 설계와 정량 점수화

유저마다 100ms 틱 루프를 인메모리로 돌리는 엔진이 동시 접속 한 자릿수에서 메모리를 밀어내며 넘어졌습니다. 고치기 전에 k6로 같은 붕괴를 재현해 원인을 확정하고, 상태를 RDS와 DynamoDB로 빼내 플래그 롤아웃으로 무중단 전환했습니다. 그 다음 질문인 '어떻게 수평 확장할 것인가'는 9개 후보를 5축으로 점수화한 설계 문서로 답했습니다.

상황

이식된 엔진에는 메모리 관리가 없었습니다. 세션과 캐릭터 기억이 eviction이나 TTL 없이 쌓이다가 OOM-killer가 프로세스를 죽이는 일이 반복됐고, 상태가 전부 프로세스 안에만 있어 재시작마다 유저 데이터가 사라질 수 있는 구조적 위험이 있었습니다.

발견은 흩어져 있었고 '무엇부터 어떤 순서로' 고칠지가 불명확했습니다. 리팩터링이 기존 동작을 깨뜨릴 위험도 컸습니다. 배포·확장 때마다 연결이 끊기는 문제까지 겹쳐, 무상태로 재설계할지 stateful을 유지하며 소유권을 다룰지가 토폴로지 전체를 가르는 미결 결정이었습니다.

한 일

  1. 01

    전수 감사와 단일 로드맵

    운영·보안·데이터·성능 14개 트랙에서 60개 이상의 발견을 심각도·file:line·수정안으로 매핑하고, 단계×의존성×위험도로 묶어 P0~P10 하나의 실행 로드맵으로 만들었습니다. P0은 코드 변경 0의 골든 스냅샷 회귀 그물(불변식 #0)이라, 이후 모든 리팩터링이 동작을 보존하는지 머지 게이트에서 검증됩니다.

  2. 02

    재현: 고치기 전에 증명

    로컬 측정에서 기억 배열이 12분 만에 170개에서 1,554개로 불어나는 것을 확인했고, k6로 20VU p95 90ms에서 버티다 50VU에서 붕괴하는 지점을 실측했습니다. OOM의 원인이 'eviction 부재 → 세션 무한 누적 → SIGKILL'의 구조적 귀결임을 숫자로 고정한 뒤에야 설계를 바꿨습니다.

  3. 03

    재설계·구현: 상태를 프로세스 밖으로

    RAM에는 상한이 있는 워킹셋만 남기고, 캐릭터 기억은 RDS PostgreSQL에 append 전용으로 영속화(복합 recency 인덱스 · ON CONFLICT UPSERT 멱등 쓰기 · 게임 시각 정렬 LIMIT N 로드)했으며 런타임 상태는 DynamoDB로 옮겼습니다. 전환은 기능 플래그로 경로를 나눠 단계적으로 진행해 중단이 없었습니다. 마이그레이션 계획은 스크래치 DB에 실제로 적용해 검증했습니다(53테이블 · 174인덱스 · CONCURRENTLY 31).

  4. 04

    수평확장 설계: 9개 후보, 5개 축

    무상태 외부화와 stateful 유지 두 패러다임 아래 단일 모놀리스, 릴레이+동적 소유권, 샤딩 액터, 웜풀 하이버네이션, 이벤트 버스, EKS StatefulSet 등 9개 후보를 각각 토폴로지로 그리고 feasibility · distinctness · scalability · opsSimplicity · realtimeFit 5축으로 점수화했습니다(모놀리스 76 · 릴레이 70 · 샤딩 68). split-brain 방지 fence를 dispose-save뿐 아니라 in-tick DB row 레벨까지 밀어야 함을 실제 세션 매니저 코드와 대조해 규명했고, 배제안(이벤트소싱 · Agones)의 근거를 결정 로그로 남겼습니다.

  5. 05

    엔진 소유권 lease 재설계

    이후 세션 소유권을 '계약 고정'에서 '저장 경계 분리'로 다시 긋는 연쇄 작업을 맡아, 배포와 확장 중에도 세션이 끊기지 않는 기반을 만들었습니다.

결과

  • 동시 활성 세션 수용력을 한 자릿수에서 세 자릿수(피크 116)로, 무중단.
  • 캐릭터 기억 1,206,886행 영속화 계층 운영, DB 마이그레이션 43개 무사고 적용.
  • 트래픽 10배 급증 구간에서도 에러율 0.05% 이하를 유지하는 구조적 기반.
  • '무상태로 시작 후 단계적 확장' 결정을 뒷받침하는 9안 설계 문서(736줄, 단독 저작)와 월 비용 대역($190~330) 비교표.
  • 골든 스냅샷 머지 게이트로 회귀 없는 리팩터링 체계 도입.

정직하게 적어 두는 것

  • 게임 도메인·내부 식별자는 비공개입니다. 유저 데이터 영향은 '구조적 위험'까지만 공개합니다.

구조

Mermaid로 작성

개선 전 → 후: 상태를 프로세스 밖으로

다이어그램 렌더링 중…

수평확장 후보 중 하나: 릴레이 + 동적 소유권

연결을 보유하는 릴레이 티어와 인메모리 틱을 도는 엔진 티어를 나누고, Redis 레지스트리로 세션 소유권을 lease로 다룹니다.

다이어그램 렌더링 중…

링크