국면 전환 자동 종료 기능
종료 알림 중복 4회→1회진행 중인 국면 전환의 종료 조건을 주기적으로 확인해, 조건 충족 시 자동 종료하는 스케줄러 기반 기능
JavaSpringRedisAOPWebSocket
아키텍처
개요
- 멀티 인스턴스 환경에서 국면 종료 조건을 주기적으로 확인하는 스케줄러 기능
- 분산 락을 획득한 단일 인스턴스만 종료 로직 수행
문제
- 모든 인스턴스에서 동일 스케줄러가 같은 주기로 실행
- 종료 조건 도달 시 여러 인스턴스가 동시에 상태 변경 시도
- DB 동시 접근으로 Race Condition 발생 가능
- WebSocket 종료 알림 중복 발송으로 UI 상태 불일치 가능성 발생
해결 전략
- Redis 기반 분산 락으로 단일 인스턴스만 종료 로직 실행
- 락 획득 인스턴스만 종료 상태 변경과 알림 처리
- 스케줄러별 락 획득·해제 중복을 AOP 기반 공통 로직으로 분리
- 작업 p99보다 긴 TTL을 두고, 해제는 Lua 스크립트로 락 value 비교 후 삭제를 원자적으로 수행해 TTL 만료 직후 타 인스턴스의 락을 잘못 지우는 오해제 방지
- 종료 상태 변경은
WHERE status = 'RUNNING'조건부 UPDATE로 멱등 처리해, 락이 깨지는 예외 상황(GC STW·TTL 만료 등)에도 중복 상태 변경을 차단
기술 선택 이유
-
Redis 분산 락
- 여러 서버 인스턴스가 공유 가능한 단일 락 저장소 필요
- 기존 인프라에서 Redis를 사용 중이라 빠른 적용 가능
- 스케줄러 실행 시간이 짧아 DB Lock보다 가벼운 제어 방식 적합
-
AOP 공통화
- 스케줄러마다 반복되는 락 획득·해제 코드 제거
- 신규 스케줄러 추가 시 애노테이션 선언만으로 동일 정책 적용
-
조건부 UPDATE (멱등성)
- 분산 락은 충돌 확률을 크게 낮추지만 GC STW·TTL 만료 시 두 인스턴스가 동시에 진입할 수 있어 단독으로는 정확성을 보장하지 못함
- 종료 상태 전이를 조건부 UPDATE로 멱등하게 만들어, 락이 깨져도 최종 상태 정합성을 지키는 2차 방어선 확보
검증
테스트 설정
- 실제 멀티 인스턴스(4개) 환경에서 스케줄러 단일 실행과 알림 중복 여부 확인
- 락 획득 실패와 TTL 만료 전 정상 해제 시나리오 확인
- 종료 처리와 WebSocket 알림 발송 여부를 함께 검증
측정 결과
- 락 미적용 시 4개 인스턴스에서 종료 WebSocket 알림이 4회 중복 발송되는 것을 재현 → 락 적용 후 1회로 수렴
- 종료 로직 단일 실행 확인
- 중복 상태 변경과 중복 알림 제거
배운 점
- 분산 락만으로는 GC STW·TTL 만료 시 단일 실행을 완전히 보장할 수 없어, 멱등한 상태 전이(조건부 UPDATE)를 더해야 정확성이 완성됨
- 락 해제는 Lua로 value 비교·삭제를 원자화해야 TTL 만료 직후의 오해제를 막을 수 있음
- AOP 공통화로 신규 스케줄러에도 동일한 락 정책을 일관되게 적용