Spring Boot와 Redis ZSET을 활용한 실시간 1:1 매칭 대기열 구현하기
서론
“Spring Boot와 Redis ZSET을 활용한 실시간 1:1 매칭 대기열 구현하기”
이 글은 해당 기술을 직접 도입하고 다듬으면서 겪은 실무 경험과 이해를 담고 있다.
부족한 내용이 있을 수 있지만, 나처럼 막 시작한 사람에게는 도움이 될 거라 생각한다.
1. 문제
graph LR\n Client[Client] -- ZADD userId timestamp --> Queue[(Redis ZSET)]\n Worker[Matching Worker] -- ZRANGE oldest candidates --> Queue\n Worker -- validate and remove atomically --> Queue\n Worker --> Room[Create matching session]
동시 매칭 요청이 겹치면 대기 순서가 어긋나거나 특정 요청의 대기 시간이 길어질 수 있습니다.
데이터베이스만으로 대기열을 처리하면 잠금 경합과 재시도로 지연이 커지고, 선착순 공정성을 유지하기 어려울 수 있습니다.
2. 왜 필요한가
공정하고 빠른 매칭 시스템은 서비스의 첫인상을 결정짓는 가장 중요한 요소입니다.
도착 순서를 유지하면서 조건에 맞는 후보를 예측 가능한 시간 안에 찾는 것이 핵심입니다.
3. 기대효과
처리량과 대기 시간 목표는 서버 수, Redis 지연, 매칭 조건을 포함한 부하 테스트로 검증해야 합니다.
부하 테스트로 정한 목표 범위 안에서 대기 시간을 관찰하고 병목을 조정할 수 있습니다.
4. 구현 방향
요청 도착 시간을 score로 사용하는 Redis ZSET 기반 대기열을 도입합니다.
가장 오래 기다린 후보를 먼저 조회하되, 조회·검증·삭제가 경쟁 요청과 겹치지 않도록 원자성을 보장하는 로직이 필요합니다.
String queueKey = "matching:queue";\ndouble score = System.currentTimeMillis();\nredisTemplate.opsForZSet().add(queueKey, userId, score);\n\nSet<String> candidates = redisTemplate.opsForZSet().range(queueKey, 0, 1);\nif (candidates != null && candidates.size() == 2) {\n // 실제 운영에서는 Lua script 또는 transaction으로 조회·검증·삭제를 원자화한다.\n matchAtomically(queueKey, candidates);\n}
5. 비즈니스 가치
ZSET은 도착 순서 기반 후보 조회를 단순화하지만, 처리 한계와 장애 복구 방식은 실제 부하 조건에서 별도로 검증해야 합니다.
매칭 지연과 이탈률은 운영 지표로 함께 관찰해 개선 효과를 판단합니다.
공식 문서와 검증 범위
명령 특성과 시간 복잡도는 Redis Sorted Sets 공식 문서를 기준으로 확인했습니다. 실제 처리량과 매칭 지연은 배포 환경의 부하 테스트 결과가 있을 때만 수치로 제시합니다.
함께 읽으면 좋은 글
- [백엔드 아키텍처] Spring Boot @Async와 ThreadPool을 활용한 대규모 트래픽 병목 해소
- Flutter Isolate로 UI Jank 줄이기
- Redis Pub/Sub을 활용한 분산 서버 동기화 운영 가이드
공식 문서와 확인 자료
아래 1차 자료를 기준으로 명령 동작과 적용 조건을 다시 확인할 수 있습니다.