Spring Boot 기반 멀티모듈 MSA 구조에서 슬롯 게임 서비스를 개발했다. 슬롯 게임 로직, 관리자 어드민, 메타 데이터 서비스가 Gradle 멀티모듈로 분리된 구조다. 2025년 한 해 동안 신규 게임 5종 출시와 엔진 구조 개선을 병행했다.
| 항목 | 내용 |
|---|---|
| 기술 스택 | Spring Boot 3.5.6 / Java 17→21 / MySQL 8.x / Redis |
| 테스트 | JUnit 5, Spock |
| 주요 관심사 | 슬롯 게임 엔진, 시뮬레이터, RCC 시스템, 잭팟 |
슬롯마다 페이 방식(라인, 웨이, 클러스터)이 다른데 각 슬롯이 이를 직접 구현하고 있었다. 5종 이상 개발하다 보니 중복 코드가 쌓였고, 신규 슬롯을 만들 때마다 같은 패턴을 반복했다.
SlotTemplate을 도입해 페이 방식을 추상화했다.
// 이전: 각 슬롯이 페이 계산 직접 구현
public class Slot47Service implements SlotService {
public SpinResult spin(...) {
// 웨이 계산 로직 직접 작성
}
}
// 이후: 템플릿이 페이 방식을 추상화
public abstract class BaseSlotService implements SlotService {
protected abstract PayResult calculatePay(Window window, SlotConfig config);
}
처음부터 설계하려 했으면 과도한 일반화로 흘렀을 것 같다. 5종 이상 직접 구현하고 나서야 공통점이 보였다.
슬롯별로 시뮬레이터가 각각 따로 구현되어 있었다. 멀티스레드로 돌리는데 잭팟풀을 전체 스레드가 공유하지 않고 각 스레드가 따로 들고 있었다. 실제 RTP(Return to Player) 계산이 슬롯마다 달랐고 집계 로직도 중구난방이었다.
ReactiveSimulator 공통 템플릿을 만들어 8종 이상 전환했다.
시뮬레이터를 먼저 만들면 게임 로직의 엣지 케이스가 먼저 드러난다. 템플릿화 이후로 버그 발견이 빨라졌다.
기존 개인화 데이터는 베팅 인덱스에 종속되어 있었다. 유저가 베팅을 바꾸면 상태가 초기화되는 문제가 있었고, 슬롯에 따라 이 동작이 맞지 않는 경우가 있었다.
베팅 인덱스와 무관한 전역 개인화 데이터 구조를 별도로 설계했다.
핵심은 마이그레이션 설계를 처음부터 같이 했다는 점이다. 기존 데이터 보유 유저에 대한 마이그레이션 없이 배포하면 운영에서 터진다. 실제로 초기 유저 케이스 버그를 마이그레이션 로직에서 잡았다.
유저가 일정 수준의 RTP(Return to Player)를 보장받을 수 있도록 RTP를 강제 제어하는 기능이다. 슬롯 플랫폼에 없던 개념으로 처음부터 설계했다.
NoOpJackpotService — EPIC_WIN이 쌓이지 않는 슬롯 예외 처리용동시성은 DB 유니크 키 + 예외 처리 조합으로 해결했다. 처음엔 낙관적 락을 고려했는데, 생성 빈도 특성상 충돌이 드물어 이 방식으로 충분했다.
슬롯마다 ExtraConfig를 직접 생성하고 있었는데, 이걸 각 슬롯별로 분리할 수 있도록 구조를 바꿨다.
이전: SlotConfigFactory가 모든 슬롯 config 생성 로직을 알고 있음
이후: 각 슬롯이 자신의 ExtraConfig 구현체를 가짐
메타 서비스로 config API를 이관하는 작업도 같이 진행 중인데, 응답 객체 모듈 이동을 먼저 해두고 실제 이관은 순차적으로 진행 중이다.
바이피처(Buy Feature) 옵션 파싱이 슬롯마다 각각 구현되어 있었다. 이걸 추상 클래스에서 제공하도록 바꾸고, 각 슬롯은 옵션 정의만 내려주는 구조로 변경했다.
| 증상 | 원인 | 해결 |
|---|---|---|
| 시뮬레이터 RTP가 실제와 다름 | 잭팟풀이 스레드별로 격리됨 | 잭팟풀 공유 상태로 변경 |
| StaticDataLoader refreshAll 후 NPE | 갱신 중 다른 스레드가 null 참조 | 갱신 완료 후 교체하는 방식으로 변경 |
| WAY 슬롯 치트 적용 시 오류 | 1릴 Wild 치트 파라미터 검증 누락 | 검증 로직 추가 |
| 바이피처 티켓 구매 불가 | 상태 조건 검사 로직 오류 | 시뮬레이터 포함 조건 수정 |
| 전역 개인화 데이터 초기 유저 오류 | 마이그레이션 시 신규 유저 케이스 미처리 | 초기 유저 분기 처리 추가 |