개발 블로그
← 블로그 목록

LOL 전적 통계 사이트 개발기 — 전체 아키텍처 구성


등록된 소환사들의 LOL 랭크 변동, 매치 히스토리, 챔피언 통계를 실시간으로 추적하는 전적 통계 서비스입니다. 단순한 API 래퍼가 아니라 데이터를 직접 수집·저장하고 여러 컴포넌트가 연동되는 구조로 만들었습니다.

전체 아키텍처

┌──────────────────────────────────────────┐
│          클라이언트 (브라우저)              │
│        React SPA + SSE 연결               │
└─────────────────┬────────────────────────┘
                  │ HTTPS
┌─────────────────▼────────────────────────┐
│                 Nginx                    │
│     리버스 프록시 + SSL (Let's Encrypt)   │
└─────────────────┬────────────────────────┘
                  │
┌─────────────────▼────────────────────────┐
│             lol-api (Spring Boot)         │
│  - 소환사/랭크/매치 조회 API              │
│  - SSE Emitter 브로드캐스트               │
│  - RabbitMQ 리스너 (이벤트 수신)          │
└──────┬────────────────────────┬──────────┘
       │                        │
┌──────▼──────┐        ┌────────▼────────┐
│  PostgreSQL  │        │  Redis          │
│  (데이터 저장)│        │  (SSE pub/sub)  │
└─────────────┘        └────────▲────────┘
                                │ pub
┌───────────────────────────────┴──────────┐
│          lol-collect (Spring Boot)        │
│  - 5분마다 랭크·매치 폴링                  │
│  - 게임 시작/종료 감지                     │
│  - Redis pub (SSE 이벤트 발행)             │
│  - RabbitMQ publish (알림 이벤트)          │
└───────┬───────────────────┬──────────────┘
        │                   │ RabbitMQ
        │              ┌────▼────────────────┐
        │              │  lol-discord-api     │
        │              │  (Spring Boot)       │
        │              │  - RabbitMQ 리스너   │
        │              │  - Discord Webhook   │
        │              └─────────────────────┘
        │
┌───────▼─────────────────────────────────┐
│        lol-riot-api (Spring Boot)        │
│  - Riot Games API 호출 전담              │
│  - Rate Limit 관리 · 요청 큐잉            │
└───────────────┬─────────────────────────┘
                │
        Riot Games API

컴포넌트별 역할

Nginx — 진입점

모든 트래픽의 진입점입니다. Let's Encrypt SSL 인증서를 적용하고, React 빌드 파일은 정적으로 서빙, API 요청은 Spring Boot로 프록시합니다. 맥미니 홈서버에 Docker 컨테이너로 운영 중입니다.

React SPA — 프론트엔드

소환사별 랭크 현황, 매치 히스토리, 챔피언 통계를 보여주는 SPA입니다. SSE(Server-Sent Events)로 서버와 연결을 유지해서 새로운 데이터가 생기면 페이지 새로고침 없이 실시간으로 업데이트됩니다.

lol-api — 메인 API 서비스

프론트엔드와 직접 통신하는 Spring Boot 서비스입니다.

  • 소환사 관리, 랭크 히스토리, 매치 조회 API 제공
  • SSE Emitter로 실시간 이벤트 브로드캐스트
  • Redis Sub — lol-collect가 발행한 이벤트를 구독해서 SSE로 클라이언트에 전달
  • RabbitMQ 리스너 — 알림 이벤트 수신 처리
  • PostgreSQL에 소환사 정보, 매치 히스토리, 랭크 변동 저장

lol-collect — 수집 서버

데이터 수집과 이벤트 발행을 전담하는 Spring Boot 서비스입니다.

  • 5분마다 스케줄러로 등록된 소환사의 랭크·매치 데이터 갱신
  • 게임 시작/종료 감지 후 Redis Pub으로 SSE 이벤트 발행 → lol-api가 구독해서 클라이언트에 전달
  • 랭크 변동, 게임 시작/종료 이벤트를 RabbitMQ에 publish
  • PostgreSQL에 수집된 데이터 저장
  • lol-riot-api 서비스를 통해 Riot Games API 호출

lol-riot-api — Riot API 래퍼

Riot Games API 호출을 전담하는 별도 서비스입니다. Rate Limit 관리, 요청 큐잉, 재시도 로직을 여기서 처리합니다. 수집 서버와 분리한 이유는 Rate Limit 초과 시 수집 로직 전체에 영향이 가지 않도록 하기 위해서입니다.

// Riot API Rate Limit: 초당 20회, 2분당 100회
// 요청 큐에 넣고 순차 처리
GET /riot/account/v1/accounts/by-riot-id/{gameName}/{tagLine}
GET /lol/league/v4/entries/by-summoner/{encryptedSummonerId}
GET /lol/match/v5/matches/by-puuid/{puuid}/ids?count=20
GET /lol/match/v5/matches/{matchId}

PostgreSQL — 영구 저장소

수집된 모든 데이터를 저장합니다. 소환사 정보, 매치별 상세 데이터, 랭크 변동 히스토리, 챔피언별 통계가 쌓입니다. MyBatis로 SQL을 직접 작성해서 복잡한 통계 쿼리도 유연하게 처리합니다.

Redis — SSE Pub/Sub

lol-collect가 게임 시작/종료 등 실시간 이벤트를 Redis에 Publish하면, lol-api가 Subscribe해서 연결된 클라이언트에게 SSE로 푸시합니다. 수집 서버와 API 서버가 물리적으로 분리되어 있어도 실시간 이벤트를 전달할 수 있는 구조입니다.

RabbitMQ — 알림 이벤트 큐

랭크 변동, 게임 시작/종료 이벤트를 메시지 큐로 처리합니다. lol-collect가 이벤트를 publish하면 lol-api와 discord-api가 각각 리스너로 구독해 처리합니다. 직접 호출 대신 큐를 사이에 두면 알림 발송 실패 시 재처리가 가능하고 서비스 간 결합도가 낮아집니다.

lol-discord-api — Discord 알림 서비스

RabbitMQ 리스너로 이벤트를 수신해서 Discord 채널로 알림을 보내는 전담 서비스입니다. Webhook URL로 POST 요청만 보내면 되는 단순한 연동이지만, 별도 서비스로 분리해서 알림 로직 변경이 다른 서비스에 영향을 주지 않도록 했습니다.

// 랭크 변동 알림 메시지
"🏆 {소환사명} 골드 IV → 골드 III 승급!"
"📉 {소환사명} 실버 I → 골드 IV 강등"
"🎮 {소환사명} 게임 시작 — 챔피언: 야스오"
"✅ {소환사명} 게임 종료 — 결과: 승리"

TFT 지원

LOL 외에 팀파이트 택틱스(TFT)도 지원합니다. Riot API는 LOL과 TFT가 별개의 엔드포인트를 사용하지만 전체 구조는 같습니다. TFT 특유의 증강, 특성, 유닛 데이터도 별도로 수집합니다.

Riot API Production Key

개인 개발 키는 하루 지나면 만료됩니다. 지속 운영하려면 Production Key를 신청해야 합니다. 서비스 목적과 사용 계획을 영어로 작성해 제출하면 1~2주 내 심사 결과가 나옵니다. Production Key는 Rate Limit이 훨씬 넉넉하고 만료가 없습니다.

현재 서비스: lol.rhdldn.com에서 운영 중입니다.