MMO 서버 아키텍처 설계

Jaemyeong Lee·2025년 2월 13일

게임 서버1

목록 보기
139/220

아키텍처 목표부터 정하자

MMO 서버의 핵심 목표

  • 정합성: 같은 입력이면 같은 월드 상태가 나와야 함
  • 지연 제어: 피크 상황에서도 틱 지연이 폭증하지 않아야 함
  • 확장성: 동접 증가 시 구조를 갈아엎지 않고 확장 가능해야 함

설계 원칙

  1. 네트워크 처리와 게임 로직 실행을 분리한다.
  2. 상태의 단일 소유자(Single Writer)를 명확히 둔다.
  3. 공유 메모리보다 메시지/큐 전달을 우선한다.

세션/유저/월드 책임 경계

책임 분리

컴포넌트책임하지 말아야 할 일
Session소켓, 송수신 버퍼, 연결 상태게임 규칙 판정
User/Player계정/캐릭터 식별, 로그인 상태소켓 I/O 직접 처리
World/Zone위치, 전투, AI, 오브젝트 상태저수준 네트워크 API 호출

매니저의 역할

  • SessionManager: 세션 생성/조회/종료, 브로드캐스트 대상 추출
  • UserManager: 계정/캐릭터 맵핑, 로그인 중복 제어
  • 핵심은 "중앙 집중"이 아니라 명확한 소유권과 조회 경로입니다.

실수 방지 규칙

  • Session*를 전역 어디서나 수정 가능하게 두지 마세요.
  • 쓰기 권한은 담당 스레드/도메인으로 제한하세요.

스레드 분배와 데이터 흐름

권장 기본 구성

역할담당 스레드출력
Accept/ConnectAccept 전담신규 Session
I/O 완료 처리IOCP WorkerPacket/Event Job
게임 로직Logic Thread(들)상태 갱신 + Send 요청
DB 작업Async DB Worker저장 결과 Job

데이터 흐름

flowchart LR
    N[IOCP Worker\n네트워크 완료 처리] --> J[Job Queue]
    J --> L[Logic Thread\n월드 상태 갱신]
    L --> S[Send Queue]
    S --> N
    L --> DQ[DB Queue]
    DQ --> D[DB Worker]
    D --> J

핵심 경계

  • IOCP 워커는 "파싱/검증/Job 생성"까지, 게임 규칙 실행은 로직 스레드에서 수행
  • DB 응답도 직접 상태 변경하지 말고 Job으로 되돌려 처리

Job Queue 패턴 (락 폭발 방지)

왜 필요한가

  • 워커가 곧바로 게임 상태를 수정하면 공유 락이 급증합니다.
  • Job Queue로 넘기면 로직 스레드가 순차 처리하여 정합성과 단순성을 얻습니다.

최소 흐름

// IOCP 워커
Packet p = DecodePacket(session, bytes);
logicQueue.Push(MakeJob(sessionId, std::move(p)));

// 로직 스레드
while (logicQueue.TryPop(job)) {
    ExecuteGameRule(job);
}

운영 포인트

  • 큐 길이 상한(Backpressure) 없으면 피크 시 메모리 급증
  • 큐 지연 시간(enqueue -> execute)을 지표로 반드시 수집

존/샤드/심리스(Seamless) 설계

Zone ownership

  • 존마다 로직 스레드 하나를 두고 해당 존 상태를 단일 소유하게 하면 락이 크게 줄어듭니다.
  • 플레이어/몬스터는 "현재 존 소유자"가 결정합니다.

경계 이동(핸드오프)

  1. 원존이 이동 이벤트 생성
  2. 대상 존 큐로 전달
  3. 대상 존이 상태 인수 후 소유권 전환
  4. 클라이언트에게 전환 결과 통지

심리스의 난제

  • 경계 부근에서 동시 전투/충돌 처리 책임이 모호해집니다.
  • 실무에서는 포탈/채널 분리로 단순화하거나, 액터 모델·이중버퍼로 복잡도를 감당합니다.

DB와 외부 시스템 연동

금지 패턴

  • 로직 스레드에서 동기 DB 호출 금지(틱 스톨 발생)

권장 패턴

  • 로직 -> DB 요청 큐 -> DB 워커 -> 결과 Job 반환
  • 타임아웃/재시도/중복 요청 방지 키(idempotency key) 설계를 함께 둡니다.

저장 전략

  • 중요 데이터(인벤토리, 재화)는 즉시성/내구성을 우선
  • 부가 데이터(통계, 로그)는 배치/비동기 적재로 분리

규모별 권장 로드맵

단계권장 구조전환 신호
1단계(프로토타입)단일 로직 스레드 + IOCP + Job Queue큐 지연/틱 지연이 피크에서 급증
2단계(성장기)존 단위 로직 스레드 + DB 워커 확장특정 존 과부하, 핫스팟 지속
3단계(대규모)샤드/채널 분산 + 메시지 버스 + 운영 자동화단일 프로세스 수직 확장 한계

강의 시 유의사항

강조 포인트

  • 아키텍처 품질은 "락 개수"가 아니라 "소유권 경계 명확성"으로 판단하세요.
  • IOCP 워커에서 게임 로직을 실행하지 않는 이유를 반드시 사례로 설명하세요.
  • 심리스 월드는 기술 이슈와 기획 이슈가 동시에 존재합니다.

자주 하는 오해

오해바로잡기
락만 잘 걸면 확장된다공유 상태가 많으면 락 자체가 병목이 된다
IOCP 쓰면 아키텍처는 끝났다로직 분리/큐 설계/운영 지표가 더 중요하다
존 분할은 기술만으로 해결 가능콘텐츠 동선/기획과 함께 설계해야 한다

체크 질문 (스스로 답해보기)

  • 현재 프로젝트에서 Session, Player, World의 쓰기 소유권은 어디에 있는가?
  • 로직 스레드가 멈추지 않도록 DB 연동을 어떤 큐 구조로 분리할 것인가?
  • 존 경계 이동 시 소유권 이전 순서를 코드로 어떻게 강제할 것인가?

profile
李家네_공부방

0개의 댓글