88 개의 글이 있습니다.

지연 시간 0ms를 보장하는 Transactional Outbox 도입기

2026년 03월 08일 01:03

DB 커밋은 됐는데 이벤트가 사라진다 ZZOL은 실시간 멀티플레이어 게임 서비스다. 방 생성, 룰렛 스핀, 미니게임 결과 같은 핵심 비즈니스 이벤트를 Redis Stream으로 브로드캐스트해서 WebSocket 클라이언트에게 전달하는 구조로 되어 있다. 문제는 에 있었다. 이 코드의 문제는 두 가지다. 첫째, 가 트랜잭션 커밋 전에 호출된다. 트랜잭션이 …


비동기 컨텍스트 전파의 두 단계: 외부 브로커 경유와 내부 스레드풀 전파 분리하기

2026년 03월 06일 05:03

ZZOL의 모든 유저 액션은 Redis Stream을 경유한다. WebSocket으로 들어온 요청이 Redis Stream에 발행되고, 별도 스레드풀에서 소비되어 게임 로직이 실행된다. 이 구조에서 한 가지 문제가 있었다. 유저 요청의 시작부터 끝까지를 하나의 trace로 추적할 수 없었다. 분산 추적이 왜 필요한가 ZZOL은 실시간 멀티플레이어 게임 서…


게임 이벤트가 100ms 늦게 도착하는데 아무도 몰랐다 — Redis Stream 관측 가능성 확보기

2026년 03월 03일 07:03

ZZOL의 모든 실시간 이벤트는 Redis Stream을 통해 흐른다. 방 입장, 카드 선택, 레이싱 탭 커맨드까지. 그런데 이 파이프라인에 대한 관측 지표가 하나도 없었다. 메시지가 100ms 늦게 도착해도, 스레드풀 큐가 80% 찼어도, 아무도 모르는 상태였다. 이 블라인드 스팟을 메트릭으로 채운 과정을 기록한다. 기존 모니터링이 놓치고 있던 것 Gr…


모든 이벤트가 같은 스레드풀을 쓸 필요는 없다: 순서 보장과 처리량 사이의 딜레마

2026년 03월 02일 03:03

ZZOL의 모든 실시간 이벤트는 Redis Stream을 통해 흐른다. 방 생성, 입장, 카드 선택, 미니게임, 레이싱 탭 — 5개 스트림이 각각의 리스너로 메시지를 소비한다. 처음에는 하나의 스레드풀로 전부 처리했다. 그러다 특정 이벤트의 특성 때문에 스레드풀을 분리해야 하는 상황이 생겼고, "어떤 스트림에 어떤 풀을 배정하는가"를 설계한 과정을 기록한…


분산 락의 함정: 락을 걸었는데도 이벤트가 두 번 처리된 이유

2026년 03월 01일 11:03

ZZOL에서 Redis Stream을 이벤트 버스로 사용하고 있다. 방 생성, 게임 시작, 룰렛 결과 등 거의 모든 도메인 이벤트가 Redis Stream을 통해 흐른다. 그런데 이벤트가 두 번 이상 도착할 수 있다는 사실을 인지했고, 이를 해결하기 위한 멱등성 처리를 설계한 과정을 기록한다. 문제 인식: 이벤트가 왜 두 번 오는가 처음에는 이벤트 중복을…


"재시작하면 고쳐져요"라는 말을 없애기까지: 3단계 서버 자가 치유기

2026년 02월 21일 03:02

"장애가 발생했습니다. 서버 재시작할까요?" 서비스 초기, 개발자라면 누구나 한 번쯤 장애 알림을 보고 무의식적으로 재시작을 한 경험이 있을거다. 하지만 단일 인스턴스에서 강제 재시작은 곧 100% 다운타임을 의미하고, 이걸 어떻게 해결할까 고민했던 과정을 기록해본다. custom_health_check 글에서 커스텀 HealthIndicator와 3단계…


HealthIndicator에는 무엇을 담아야 하는가: 상태 판별부터 자가 치유까지

2026년 02월 19일 09:02

ZZOL 서비스에 커스텀 HealthIndicator와 자가복구(Self-Recovery) 로직을 추가하고, Health Group을 분리했다. Spring Boot의 기본 헬스체크가 어디까지 커버하고, 어디서부터 커스텀이 필요한지, 장애 감지 후 Docker 재시작 전에 애플리케이션 내부에서 먼저 복구를 시도해야 하는 이유, 그리고 DOWN과 OUT_O…


ZZOL의 효율적인 서버 자기보호 전략

2026년 02월 18일 12:02

ZZOL 서비스에 Rate Limiting을 적용했다. 단순히 "요청을 제한하자"가 아니라, 같은 서버 보호인데 HTTP와 WebSocket에서 왜 다른 전략을 써야 하는지, 각 설정값을 왜 그렇게 잡았는지에 대한 판단 과정을 기록한다. 왜 서버 자기보호가 필요했는가 ZZOL은 실시간 멀티플레이어 게임 서비스다. 점심시간에 한 팀이 모여서 미니게임을 하고…


외부 서비스 장애로부터 살아남기

2026년 02월 17일 09:02

에서 외부 서비스 장애 대응 작업을 했다. Oracle Object Storage에 QR 코드를 업로드하는 과정에서, 외부 서비스가 불안정할 때 시스템 전체가 영향을 받는 문제가 있었다. 이 글에서는 Circuit Breaker와 Retry를 도입하면서 고민한 과정을 기록해본다. 문제 상황 ZZOL에서는 방을 생성할 때 QR 코드를 만든다. 이 QR 코드…


네트워크 불안정 상황에서도 메시지 유실 없는 견고한 게임 서버 설계

2026년 02월 14일 09:02

실시간 멀티플레이어 게임을 개발하면서 마주친 문제가 있다. 특정 상황에서 유저가 게임 흐름에서 이탈하는 현상이었다. 이 글에서는 문제를 분석하고 해결한 과정을 공유한다. 문제 인식 유저 피드백 ZZOL은 실시간으로 여러 명이 함께 플레이하는 게임 서비스다. 배포와 동시에 여러 사람들에게 피드백을 받아왔었는데, 예상치 못한 불만이 있었다. "게임 중에 카톡…