2025년 3월 6일

김동환·2025년 3월 6일

게임 업적 시스템 구축

1. 게임 업적 시스템 설계

오늘은 분산 서버 환경에서 게임 업적을 저장하고 관리하는 시스템을 구축했다.
기존 게임 결과 저장 방식과 달리, 업적 데이터는 개별 플레이어별로 저장되어야 하며,
게임 서버 → Redis → API 서버 → RDS 순서로 데이터가 전달되는 구조를 갖는다.

2. 게임 업적 데이터 흐름

  1. 게임 종료 시 게임 서버에서 업적 데이터 생성

    • 게임 서버의 endGame 로직에서 플레이어별 능력 사용 기록, 킬 수, 생존 여부를 포함한 데이터를 수집
    • Redis gameAchievements:{gameId} 키에 저장 후, gameAchievements 채널로 Pub/Sub 전송
  2. API 서버에서 Redis Pub/Sub을 통해 업적 데이터 구독

    • GameResultsSubscriber에서 gameAchievements 채널을 구독하여 메시지를 수신
    • Redis에 해당 데이터가 존재하는지 확인 후, GameAchievementsService.saveGameAchievements() 호출
  3. API 서버에서 데이터 변환 후 RDS에 저장

    • GameAchievementsService에서 데이터를 변환하여 개별 플레이어별 레코드로 저장
    • 숫자 변환 오류를 방지하기 위해 isNaN() 체크를 추가하고 기본값을 설정

3. 주요 개선 사항

  • 데이터 구조 정리

    • 기존 gameAchievements는 JSON 형식으로 한 번에 저장되었으나, 개별 플레이어 단위로 변환하여 RDS에 저장하도록 변경
    • GameAchievement 엔티티를 업데이트하여 role, kills, abilitiesUsed, survived 필드를 포함하도록 수정
  • 데이터 변환 시 오류 방지

    • isNaN() 체크를 추가하여 killsabilitiesUsed 값이 NaN이 되는 문제 해결
    • statsundefined일 경우 경고 메시지를 출력하고 무시하도록 처리
  • Redis 중복 저장 방지

    • 이미 저장된 게임 업적 데이터인지 확인 후 중복 저장을 방지하는 로직 추가

4. 배운 점

  • 분산 서버 환경에서 데이터 흐름을 설계하는 방법

    • 게임 서버가 직접 RDS에 저장하지 않고, Redis Pub/Sub을 활용하여 API 서버로 데이터를 전송하는 구조를 이해했다.
    • 이를 통해 게임 서버의 부하를 줄이고, API 서버에서 데이터를 효과적으로 관리할 수 있다.
  • TypeORM과 TypeScript를 활용한 안전한 데이터 처리

    • isNaN() 체크와 기본값 설정을 통해 잘못된 데이터가 저장되지 않도록 방어 코드를 추가하는 것이 중요하다.
    • Object.entries().map()을 사용할 때 불필요한 데이터(null 등)를 제거하는 방법을 다시 정리했다.
  • NestJS에서 순환 의존성 문제 해결

    • GameResultsModuleGameAchievementsModule이 서로 참조하는 문제를 해결하기 위해 forwardRef()를 사용했다.
    • @Inject(forwardRef(() => ServiceName))을 통해 서비스 간의 의존성을 해결하는 방법을 다시 학습했다.

5. 다음 할 일

  • API 서버에서 업적 데이터를 조회하는 API 추가
  • 업적 데이터를 활용한 리더보드 기능 개발
  • 게임 업적 데이터를 시각화하여 플레이어에게 제공하는 기능 검토
profile
Node.js 7기

0개의 댓글