📌 개요
현재 Sorted Set 의 score 가 단순 epoch milli. 같은 millisecond 에 여러 토큰 발급 시 score 동일 → Redis 가 멤버 문자열 (UUID) 사전순으로 정렬 → 실제 발급 순서와 어긋난다.
티켓 예매 같은 초고동시성 환경에서 동시 진입자가 다수 발생 시 대기열 순서가 비결정적이 되어 사용자 경험 / 공정성에 영향을 준다.
🎯 목표
🧩 리팩토링 범위
🏗️ 변경 설계
변경 전 구조
long issuedAtEpochMilli = token.getIssuedAt().toEpochMilli();
operations.opsForZSet().add(programKey, tokenIdStr, issuedAtEpochMilli);
→ 동일 ms 시 score 충돌 → 사전순 정렬
변경 후 구조
중간 단계 — INCR 시퀀스 추가
long counter = redisTemplate.opsForValue().increment("queue:seq:" + programId);
double score = epochMilli * 1_000_000.0 + counter;
operations.opsForZSet().add(programKey, tokenIdStr, score);
- 단조 증가 시퀀스로 결정론적 순서 보장
- 비교적 간단한 변경
최종 단계 — Lua Script tie-breaker
영향 받는 기능
enqueue() — score 계산 로직 변경
findRank() — 정확한 순번 반환
findAdmissionCandidates() — 정확한 FIFO 순서
⚠️ 주의 사항
- 기능 동작은 기존과 동일 (순서 정확성만 ↑)
- API 스펙 변경 없음
- 시퀀스 키 (
queue:seq:{programId}) 추가 — 메모리 사용 증가 미미
- 시퀀스 오버플로우 방지 (long 범위 내 충분, 우려 시 주기 리셋 검토)
🧪 검증 방법
- 기존 테스트 통과 여부 확인
- 동시 진입 테스트 추가 (같은 ms 발급 시 발급 순서 검증)
🔗 참고
📌 개요
현재 Sorted Set 의 score 가 단순 epoch milli. 같은 millisecond 에 여러 토큰 발급 시 score 동일 → Redis 가 멤버 문자열 (UUID) 사전순으로 정렬 → 실제 발급 순서와 어긋난다.
티켓 예매 같은 초고동시성 환경에서 동시 진입자가 다수 발생 시 대기열 순서가 비결정적이 되어 사용자 경험 / 공정성에 영향을 준다.
🎯 목표
🧩 리팩토링 범위
🏗️ 변경 설계
변경 전 구조
→ 동일 ms 시 score 충돌 → 사전순 정렬
변경 후 구조
중간 단계 — INCR 시퀀스 추가
최종 단계 — Lua Script tie-breaker
영향 받는 기능
enqueue()— score 계산 로직 변경findRank()— 정확한 순번 반환findAdmissionCandidates()— 정확한 FIFO 순서queue:seq:{programId}) 추가 — 메모리 사용 증가 미미🧪 검증 방법
🔗 참고
enqueue메서드는 MULTI/EXEC 트랜잭션을 사용하지만, 역인덱스(setIfAbsent)와의 원자성 문제도 존재하므로 Lua Script 도입 시 함께 처리 권장. (관련 이슈: [refactor][queue-service] enqueue/delete 로직 원자성 개선 (Lua Script 통합) #11 )