AWS-Dynamo DB를 활용하여 유저 통계 데이터 수집
백오피스에 게임별 유저 통계 차트를 붙이기 위해 AWS DynamoDB로 수집 파이프라인을 구성한 기록. 테이블 설계와 집계 방식, 백오피스 차트 연동까지 실제 구축 순서대로 정리한다.

백오피스에 게임별 유저 통계 차트를 추가한 개발기
회사에서는 주로 게임 운영을 위한 백오피스 시스템을 개발하고 유지보수하고 있습니다.
이 백오피스에는 유저 계정 관리, 게임 홈페이지의 게시글, 쿠폰 및 쿠폰 이벤트 등 GM(Gamemaster)들이 효율적으로 업무를 처리할 수 있도록 다양한 기능이 포함되어 있습니다. 또한 문의 답변률, 게임 별 게시글 수 등 다양한 차트들이 있는 대시보드도 함께 존재합니다.
최근에는 대시보드에 각 게임별 유저 통계 차트를 새롭게 추가하게 되었습니다.

차트 이미지
이 통계 차트는 특정 일자에 게임에 접속한 유저가
- 신규 유저(처음 접속한 유저)인지,
- 활성 유저(최근에도 꾸준히 접속하고 있는 유저)인지,
- 복귀 유저(90일 이상 쉬었다가 돌아온 유저)인지
를 구분하여 시각화한 것입니다.
데이터 수집을 위한 구조 이해
이 작업을 위해 가장 먼저 필요한 것은 유저 접속 로그 데이터의 수집이었습니다.
접속 로그 테이블에는 다음 정보들이 기록됩니다:
- 접속한 게임 이름
- 유저 고유 번호
- 접속 IP
- 접속 일시 (DATETIME)
이 테이블은 유저가 접속할 때마다 기록되기 때문에, 동일한 유저가 같은 날 여러 번 접속했다면 중복 데이터가 발생합니다.
따라서 중복 제거는 필수입니다.
유저의 상태를 구분하는 기준은 다음과 같습니다:
- 신규 유저: 직전 접속 기록이 없는 경우 (NULL)
- 복귀 유저: 마지막 접속일로부터 90일 이상 지난 경우
현재 하루 평균 약 3,600건의 로그가 쌓이고 있으며, 현재는 2개의 게임 데이터만 수집 중이지만 향후 6개 이상의 게임이 추가될 예정입니다.
MySQL 5.5의 제약과 고민
문제는 우리가 사용 중인 데이터베이스 버전이 MySQL 5.5.64라는 점입니다.
이 버전은 윈도우 함수를 지원하지 않기 때문에, 유저별 직전 접속일을 구하기 위해서는 테이블 전체를 스캔하거나, 서브쿼리/조인/임시 테이블을 사용하는 수밖에 없었습니다.
이는 단순히 성능 저하에 그치지 않고, 서비스 중인 웹사이트에 직접적인 부하로 이어질 수 있어 큰 리스크가 있었습니다.
특히 아래 두 작업이 병목이 되었습니다:
- 신규 유저 판별: 직전 접속 기록이 존재하는지 여부 확인
- 복귀 유저 판별: 이전 접속일과 현재 접속일 간의 일 수 계산
이 두 작업을 매일 처리하기에는 로그 테이블 특성 상 데이터가 수만개 쌓일 가능성이 있고,
더군다나 초기 데이터를 수집할 때엔 쿼리 실행에 시간을 많이 소요하게 될 것입니다.
해결책: DynamoDB 도입
결국 이 문제를 해결하기 위해 AWS DynamoDB를 도입했습니다.
다음은 전체 데이터 흐름의 개요입니다.

데이터 흐름
핵심 아이디어는 서비스 DB에서 처리하던 복잡한 연산을 DynamoDB로 이전하는 것이었습니다.
기존에는 MySQL에서 조인이나 임시 테이블을 통해 유저 상태를 판단했다면, 이제는 DynamoDB에 유저/게임별 마지막 접속 일자를 저장하고 이를 기반으로 상태를 분류합니다.
데이터 수집은 Laravel의 Command 기능과 Schedule 클래스를 활용하여 매일 새벽 1시 30분에 자동 실행됩니다.
다음 쿼리를 통해 전날 접속한 유저 중 중복을 제거한 데이터를 가져옵니다:
Log::select('game_name', 'member_id')
->selectRaw('MAX(reg_date) AS last_date')
->where('reg_date', '>=', $currentDate->format('Y-m-d'))
->where('reg_date', '<', $currentDate->copy()->addDay()->format('Y-m-d'))
->groupBy('member_id', 'game_name') ->get();
DynamoDB 테이블 설계
가져온 데이터를 순회하면서 유저와 게임을 하나의 논리적 그룹으로 묶고, DynamoDB에서 해당 유저의 마지막 접속일을 조회해 현재 접속일과 비교합니다.

생성한 테이블의 ERD
테이블 컬럼 구성은 단순합니다:
- member_id: 유저 번호 (파티션 키)
- game_name: 접속한 게임 이름 (정렬 키)
- last_login_at: 마지막 접속 일자
- recorded_at: 기록된 일자
파티셔닝 키 선택도 고민이 많았습니다.
처음에는 게임 이름을 파티션 키로 두는 것도 고려했지만, 현재는 게임 수가 적고 유저 수가 많기 때문에 유저 번호를 파티션 키로, 게임 이름을 정렬 키로 설정했습니다. 이렇게 구성함으로써 쿼리 성능을 극대화하고 필요한 데이터를 빠르게 조회할 수 있었습니다.
AWS Workbench의 활용
AWS에서는 NoSQL 데이터를 시각적으로 확인할 수 있는 Workbench를 제공합니다.

AWS NoSQL Workbench
회사 보안 정책상 AWS 계정에 직접 접속할 수 없었고, 개발 환경에서 필요한 키 설정도 제한이 있어 어려움이 있었지만,
워크벤치를 통해 직접 테이블을 생성하고 데이터 흐름을 검증할 수 있었습니다. 초기 생성된 테이블의 키 설계에 문제가 있었던 것도 시각적으로 파악할 수 있었고, 이후 키 정보를 기반으로 두 번째 테이블을 직접 생성하여 원하는 구조로 재설계할 수 있었습니다.
데이터의 삽입/삭제 여부도 눈으로 확인할 수 있어 매우 유용했습니다.
최종 데이터 저장 및 활용
이 과정을 통해 수집된 유저 상태 데이터는 Laravel의 storage 디렉토리에 파일로 저장됩니다.

데이터가 php 객체 형태로 저장된 data 파일
API에서 통계 데이터를 요청받으면, 이 수집된 파일을 기반으로 빠르게 응답할 수 있도록 구현했습니다.
DB에 직접 접근하지 않기 때문에 부하 없이 빠른 응답이 가능합니다.
마무리하며: 아키텍처 설계의 중요성
처음에는 단순하게 MySQL 내부의 프로시저로 모든 로직을 처리하려 했습니다.
하지만 낮은 MySQL 버전 제약으로 인해 임시 테이블을 사용해야 했고, 인덱싱과 성능 최적화에도 시간이 많이 소요되었습니다.
결국 전체 테이블 스캔이라는 문제는 해결되지 않았고, 이를 통해 아키텍처 설계의 중요성을 절실히 느낄 수 있었습니다.
무엇보다 이번 작업에서 가장 인상 깊었던 것은, 팀장님의 제안 덕분에 DynamoDB라는 기술을 접하게 된 것입니다.
이전에는 알지도 못했던 도구였지만, 직접 사용해보며 기술적 선택의 폭을 넓힐 수 있었고, 다양한 도구를 접하고 활용하는 것이 개발자의 중요한 자질임을 다시금 깨닫게 되었습니다.