알게된사실

Redis ZSET으로 대기열을 구현한 이유

HEEJUNDID 2026. 3. 30. 23:48
728x90
반응형

대기열에서 가장 중요한 기능은 순번 관리다.
누가 먼저 들어왔는지 정렬할 수 있어야 하고,
특정 사용자의 현재 순번도 빠르게 조회할 수 있어야 한다.

이 요구사항에 가장 잘 맞는 자료구조가 Redis의 ZSET이다.

ZSET은 다음 두 값을 함께 저장한다.

  • member
  • score

그리고 score 기준으로 자동 정렬된다.

대기열에서는 이 구조를 다음과 같이 사용했다.

  • member = userId
  • score = 사용자가 대기열에 진입한 시간

예를 들어 다음과 같이 데이터를 넣으면,

redis.opsForZSet().add("queue:1", userId.toString(), score);

Redis 내부에서는 score 기준으로 정렬된 집합이 만들어진다.
즉, 먼저 들어온 사용자가 앞 순번을 가지게 된다.

이후 특정 사용자의 순번은 ZRANK로 조회할 수 있다.

redis.opsForZSet().rank("queue:1", userId.toString());

이 값은 0부터 시작하는 rank이므로,
화면에 보여줄 순번은 보통 rank + 1로 계산하면 된다.

대기열 입장 여부는 이 순번과 gate 값을 비교해서 판단한다.

  • rank ≤ gate → 입장 가능
  • rank > gate → 대기 유지

이 구조가 좋은 이유는 대기열의 핵심 기능을 대부분 Redis가 처리해주기 때문이다.
애플리케이션에서 별도의 정렬 로직을 직접 구현할 필요가 없다.

추가로, Queue와 Token은 분리해서 저장했다.

Queue는 순서를 관리하기 위한 데이터이고,
Token은 사용자를 다시 찾기 위한 키이기 때문이다.

그래서 Redis Key는 다음과 같이 나누었다.

  • queue:{concertId} : 실제 대기열
  • gate:{concertId} : 현재 입장 허용 범위
  • qtoken:{token} : queue token 매핑
  • atoken:{token} : access token 매핑

정리하면 Redis ZSET을 사용한 이유는 간단하다.

  • 정렬된 대기열이 필요했고
  • 순번 조회가 빨라야 했고
  • 동시성 상황에서도 단순하게 운영하고 싶었기 때문이다

다음 글에서는 이 구조를 테스트 가능하게 만들기 위해 적용한 Port/Adapter 구조를 정리하려고 한다.

728x90
반응형