March 08, 2026
DB 커밋은 됐는데 이벤트가 사라진다 ZZOL은 실시간 멀티플레이어 게임 서비스다. 방 생성, 룰렛 스핀, 미니게임 결과 같은 핵심 비즈니스 이벤트를 Redis Stream으로 브로드캐스트해서 WebSocket 클라이언트에게 전달하는 구조로 되어 있다. 문제는 에 있…
March 06, 2026
ZZOL의 모든 유저 액션은 Redis Stream을 경유한다. WebSocket으로 들어온 요청이 Redis Stream에 발행되고, 별도 스레드풀에서 소비되어 게임 로직이 실행된다. 이 구조에서 한 가지 문제가 있었다. 유저 요청의 시작부터 끝까지를 하나의 tra…
March 03, 2026
ZZOL의 모든 실시간 이벤트는 Redis Stream을 통해 흐른다. 방 입장, 카드 선택, 레이싱 탭 커맨드까지. 그런데 이 파이프라인에 대한 관측 지표가 하나도 없었다. 메시지가 100ms 늦게 도착해도, 스레드풀 큐가 80% 찼어도, 아무도 모르는 상태였다. …
March 02, 2026
ZZOL의 모든 실시간 이벤트는 Redis Stream을 통해 흐른다. 방 생성, 입장, 카드 선택, 미니게임, 레이싱 탭 — 5개 스트림이 각각의 리스너로 메시지를 소비한다. 처음에는 하나의 스레드풀로 전부 처리했다. 그러다 특정 이벤트의 특성 때문에 스레드풀을 분…
March 01, 2026
ZZOL에서 Redis Stream을 이벤트 버스로 사용하고 있다. 방 생성, 게임 시작, 룰렛 결과 등 거의 모든 도메인 이벤트가 Redis Stream을 통해 흐른다. 그런데 이벤트가 두 번 이상 도착할 수 있다는 사실을 인지했고, 이를 해결하기 위한 멱등성 처리…
February 21, 2026
"장애가 발생했습니다. 서버 재시작할까요?" 서비스 초기, 개발자라면 누구나 한 번쯤 장애 알림을 보고 무의식적으로 재시작을 한 경험이 있을거다. 하지만 단일 인스턴스에서 강제 재시작은 곧 100% 다운타임을 의미하고, 이걸 어떻게 해결할까 고민했던 과정을 기록해본다…
February 19, 2026
ZZOL 서비스에 커스텀 HealthIndicator와 자가복구(Self-Recovery) 로직을 추가하고, Health Group을 분리했다. Spring Boot의 기본 헬스체크가 어디까지 커버하고, 어디서부터 커스텀이 필요한지, 장애 감지 후 Docker 재시작…
February 18, 2026
ZZOL 서비스에 Rate Limiting을 적용했다. 단순히 "요청을 제한하자"가 아니라, 같은 서버 보호인데 HTTP와 WebSocket에서 왜 다른 전략을 써야 하는지, 각 설정값을 왜 그렇게 잡았는지에 대한 판단 과정을 기록한다. 왜 서버 자기보호가 필요했는가…
February 17, 2026
에서 외부 서비스 장애 대응 작업을 했다. Oracle Object Storage에 QR 코드를 업로드하는 과정에서, 외부 서비스가 불안정할 때 시스템 전체가 영향을 받는 문제가 있었다. 이 글에서는 Circuit Breaker와 Retry를 도입하면서 고민한 과정을…
February 14, 2026
실시간 멀티플레이어 게임을 개발하면서 마주친 문제가 있다. 특정 상황에서 유저가 게임 흐름에서 이탈하는 현상이었다. 이 글에서는 문제를 분석하고 해결한 과정을 공유한다. 문제 인식 유저 피드백 ZZOL은 실시간으로 여러 명이 함께 플레이하는 게임 서비스다. 배포와 동…