[친구하자] 매칭 대기열 만들면서 정리한 Redis 명령어 치트시트 (SET/ZSET편)
친구하자 프로젝트 개발 중 랜덤 매칭 대기열을 만들면서 정리한 Redis 명령어 모음집입니다.
카테고리별 2인 매칭을 구현하며 실제로 쓴(또는 고민했던) 명령어들을 짧게 정리. 예시 키는
{cat:123}
해시태그로 Redis Cluster 슬롯을 고정하는 패턴을 사용.
ZSET (Sorted Set) — 순번/대기시간/우선순위가 필요할 때
ZADD key score member [score member ...]
멤버 추가/갱신. score가 작을수록 앞쪽.ZADD wait:z:{cat:123} 1725430000123 101
ZRANGE key start stop [WITHSCORES | REV | BYSCORE ...]
정렬 순서대로 조회. 삭제는 아님!ZRANGE wait:z:{cat:123} 0 1 # 가장 오래 기다린 2명 ZRANGE wait:z:{cat:123} 0 9 WITHSCORES # 상위 10명 + score
ZRANK key member
멤버의 순위(0-base).ZRANK wait:z:{cat:123} 101 # 0이면 1번째
ZSCORE key member
멤버의 score(대기 시작 시각 등).ZSCORE wait:z:{cat:123} 101
ZCARD key
멤버 수.ZCARD wait:z:{cat:123}
ZREM key member [member ...]
멤버 삭제.ZREM wait:z:{cat:123} 101 205
ZRANDMEMBER key [count] [WITHSCORES]
(6.2+) 무작위 조회(삭제 아님).ZRANDMEMBER wait:z:{cat:123} 2
ZPOPMIN key [count]
/ZPOPMAX
꺼내며 삭제(원자). 대기순 매칭에 유용.ZPOPMIN wait:z:{cat:123} 2
SET (집합) — 중복 없는 랜덤 풀
SADD key member [member ...]
/SREM key member [...]
추가/삭제 (중복 불가).SADD matching:queue:{cat:123} 101 SREM matching:queue:{cat:123} 101
SPOP key [count]
무작위 추출+삭제(원자). 랜덤 매칭에 간단·빠름.SPOP matching:queue:{cat:123} 2
SCARD key
멤버 수.SCARD matching:queue:{cat:123}
TTL/키 유틸 (대기 상태 자동 청소용)
SET key value EX <sec> NX
선점 + TTL(중복 입장 방지).SET user:index:42 "cat=123|queue=q_..." EX 600 NX
EXPIRE key <sec>
/TTL key
키 만료/조회. 주의: TTL은 키 전체에 붙음(멤버 단위 X).
베스트 프랙티스: 대기열 컬렉션(SET/ZSET)엔 TTL 금지, 개별 사용자 상태 키에만 TTL.
매칭에서 자주 쓰는 레시피
1) 대기순(공정성) 매칭
방법 A(2단계):
ZRANGE
로 상위 N 조회 →ZREM
로 제거ZRANGE wait:z:{cat:123} 0 1 # 후보 조회 ZREM wait:z:{cat:123} 101 205 # 확정 후 제거
방법 B(원자):
ZPOPMIN wait:z:{cat:123} 2
(조회+삭제가 한 번에)
2) 랜덤 매칭
ZSET만 쓸 때(원자화는 Lua 추천):
ZRANDMEMBER
로 조회 → 같은 로직 안에서ZREM
SET을 함께 쓸 때:
SPOP matching:queue:{cat:123} 2
(원자 랜덤 추출)
3) 하이브리드(랜덤 80% + 대기순 20%)
하나의 Lua/Functions에서 분기:
- 랜덤:
ZRANDMEMBER
→ZREM
- 대기순:
ZRANGE
→ZREM
(또는ZPOPMIN
)
- 랜덤:
4) 원자성 보장(동시성 안전)
조회(선정)와 삭제를 한 덩어리로: Lua/Functions로 감싸기
- “이미 다른 워커가 먼저 가져간” 케이스를 **
ZREM
반환값(0/1)**로 판단해 필터링.
- “이미 다른 워커가 먼저 가져간” 케이스를 **
흔한 실수 & 주의
ZRANGE
/ZRANDMEMBER
만 호출하고ZREM
을 빼먹음 → 큐에 그대로 남아 중복 매칭 발생.- 컬렉션 키에 TTL을 걸어 전체 대기열이 사라짐. TTL은 개별 사용자 키(예:
user:queued:{cat:123}:42
)에만. - Redis Cluster 사용 시, 스크립트 KEYS는 같은 해시태그(
{cat:123}
)로 묶기. 전역 키는 Lua에서 다루지 말고 자바에서만.
시간 복잡도
ZADD/ZREM/ZRANK
≈ O(log N)ZRANGE
≈ O(k) (반환 수)ZPOPMIN/MAX
≈ O(k log N)SADD/SREM/SPOP
≈ 평균 O(1)
미니 예시: 대기열 입장 & 매칭
# 입장
ZADD wait:z:{cat:123} 1725430000456 101 # 대기 시작 시각(밀리초)
SET user:queued:{cat:123}:101 q_101_123 EX 600 # 개별 TTL
# 대기순 매칭 2명 (원자)
ZPOPMIN wait:z:{cat:123} 2 # -> [101,score],[205,score]
# 랜덤 매칭 2명 (Lua로 원자화 권장)
-- 조회
ZRANDMEMBER wait:z:{cat:123} 2
-- 같은 로직 안에서 제거
ZREM wait:z:{cat:123} 101 205
한 줄 정리
- ZSET = 순번/대기시간/공정성, SET = 단순 랜덤 풀
ZRANGE/ZRANDMEMBER
(조회) 뒤엔 반드시ZREM
(삭제)- 경쟁 환경에선 Lua로 “조회→삭제”를 원자화
- TTL은 개별 상태 키에만, 대기열 컬렉션엔 금지