Stage 4 · Provision
Design Case Studies
Design a Leaderboard
Redis sorted sets, partitioned rankings, periodic snapshots, and anti-cheat data checks.
Requirements
A leaderboard tracks scores for millions of players and provides real-time ranking queries. It must support score updates at 100K QPS, ranking queries in < 50ms, and handle ties with secondary sort keys. The leaderboard must be consistent — a player sees their correct rank after updating their score.
Redis Sorted Sets
Redis sorted sets (ZSET) are the ideal data structure for leaderboards. Each member has a score. Redis maintains sorted order by score. ZRANK returns a member's rank. ZRANGE returns top-N members. All operations are O(log N).
import redis
r = redis.Redis()
# Update player score
def update_score(game_id: str, player_id: str, score: float):
key = f"leaderboard:{game_id}"
r.zadd(key, {player_id: score})
# Get player rank (0-indexed)
def get_rank(game_id: str, player_id: str) -> int:
key = f"leaderboard:{game_id}"
rank = r.zrevrank(key, player_id) # Descending order
return rank if rank is not None else -1
# Get top N players
def get_top_n(game_id: str, n: int = 10) -> list:
key = f"leaderboard:{game_id}"
return r.zrevrange(key, 0, n - 1, withscores=True)
# Get player score
def get_score(game_id: str, player_id: str) -> float:
key = f"leaderboard:{game_id}"
return r.zscore(key, player_id)
# Get players around a specific rank
def get_around_me(game_id: str, player_id: str, range: int = 5) -> list:
rank = get_rank(game_id, player_id)
key = f"leaderboard:{game_id}"
start = max(0, rank - range)
end = rank + range
return r.zrevrange(key, start, end, withscores=True)Redis ZSET provides O(log N) score updates and O(log N + M) ranking queries. This handles 100K+ QPS with sub-millisecond latency.
Partitioned Rankings
For millions of players, a single sorted set can become a bottleneck. Partition by region, game mode, or time period. Each partition has its own sorted set. Global rankings are computed by merging partitions.
Leaderboard partitions:
leaderboard:us ── Top 100K US players
leaderboard:eu ── Top 100K EU players
leaderboard:asia ── Top 100K Asia players
Global top 100:
Merge top 100 from each partition
Sort merged list
Return top 100Partitioning distributes load across multiple Redis nodes. Global rankings require merging partitions, which adds latency. Cache global rankings and refresh periodically.
Periodic Snapshots
Leaderboard data changes constantly. Take periodic snapshots to preserve historical rankings. Store snapshots in a database for historical queries: how did the ranking change over time? What was my rank last week?
Anti-Cheat Checks
- Score validation — Reject scores outside expected range.
- Time validation — Reject scores that are impossibly fast.
- Pattern detection — Flag unusual score patterns.
- Server-side verification — Validate game outcomes server-side.
- Audit trail — Log all score changes for investigation.
Global Rankings at Scale
For 100M+ players, Redis sorted sets hit memory limits. Use a two-tier approach: Redis for real-time top-N and near-top rankings, database for full rankings. Update the database periodically from Redis snapshots.
The top 1000 players are requested most frequently. Cache them in Redis with a short TTL. Most users only care about the top ranks and their own position.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.