Sorted Sets
Sorted sets (ZSET) combine a unique member with a double score — Redis maintains skip-list + hash index for O(log N) rank, range, and score queries.
Introduction
Sorted sets (ZSET) combine a unique member with a double score — Redis maintains skip-list + hash index for O(log N) rank, range, and score queries. This is the type behind leaderboards, priority queues, and time-series indexes.
ZADD updates score; ZREVRANGE returns top-N; ZRANK gives position. No other in-memory store matches this ergonomics for real-time ranking at scale.
Scores can be timestamps, points, or composite values — members are typically entity IDs.
Understanding the topic
Key concepts
- ZADD key score member — insert or update score.
- ZREVRANGE key 0 9 WITHSCORES — top 10 descending.
- ZRANGE BYSCORE — filter by score band.
- ZINCRBY — atomic score increment.
- ZRANK/ZREVRANK — position of member.
- ZREM, ZCARD — delete and count.
flowchart TBZADD --> SkipListSkipList --> ZREVRANGE[Top N query]SkipList --> ZRANK[Rank lookup]
Step-by-step explanation
- Each member appears once; score determines order.
- Skip list enables log-time rank and range.
- Same member re-ZADD updates score in place.
- Lex ordering available with special score encoding.
- Union/inter store ops merge multiple zsets.
Syntax reference
Common commands
- ZINCRBY — game points, vote counts.
- ZREVRANGE 0 9 — top 10 leaderboard.
- Score as Unix timestamp — delayed job queue.
ZADD leaderboard 9850 user:1001ZINCRBY leaderboard 50 user:1001ZREVRANGE leaderboard 0 9 WITHSCORESZRANK leaderboard user:1001
Informative example
Leaderboard service with Spring Redis ZSet ops:
@Servicepublic class Leaderboard {private final StringRedisTemplate redis;public Leaderboard(StringRedisTemplate redis) {this.redis = redis;}public void addScore(String board, String userId, double delta) {redis.opsForZSet().incrementScore("lb:" + board, userId, delta);}public Set<ZSetOperations.TypedTuple<String>> top10(String board) {return redis.opsForZSet().reverseRangeWithScores("lb:" + board, 0, 9);}}
Trim board with ZREMRANGEBYRANK if millions of players — keep top 10K only.
Real-world use
Real-world use cases
- Gaming leaderboard — ZINCRBY on match end.
- Twitter timeline rank — score = timestamp.
- Priority task queue — score = priority or run-at time.
- Rate limit sliding window — ZADD timestamp member.
- Trending topics — increment score per mention.
Best practices
- Trim large zsets — ZREMRANGEBYRANK remove low ranks.
- Use member IDs not heavy JSON as members.
- Paginate with ZREVRANGE start stop not full scan.
- Composite scores need documented encoding.
- Replicate read-heavy boards to replicas.
- Cache top-N in app for sub-ms if needed.
Common mistakes
- Millions of members never trimmed.
- Using member JSON with large payload.
- ZRANGE entire zset in API hot path.
- Float score equality bugs in range queries.
Advanced interview questions
Q1BeginnerWhat is a sorted set?
Q2BeginnerLeaderboard commands?
Q3IntermediateZSET internal structure?
Q4IntermediateDelayed queue with ZSET?
Q5AdvancedScale leaderboard to 100M users?
Summary
ZSET = Redis superpower for ranking.