Problem Overview
Design a leaderboard and matchmaking system for a multiplayer game with 50 million players. The leaderboard shows global rank and top-100 in near real-time. Matchmaking pairs players of similar skill into 10-player lobbies within 30 seconds. This question appears at game companies (Riot, Blizzard, Epic) and general backend roles at companies building competitive features.
Part 1: Leaderboard Design
Redis Sorted Set
The canonical leaderboard data structure is a Redis sorted set (ZSET). Each member is a player ID; the score is the player rating or point total. Redis ZADD is O(log N) per update. ZRANK returns a player rank in O(log N). ZREVRANGE returns the top-K players in O(log N + K). Redis keeps the set sorted at all times, so rank queries are instant.
# Update score after a match
redis.zadd("leaderboard:global", {player_id: new_score})
# Get global rank (0-indexed, use +1 for display)
rank = redis.zrevrank("leaderboard:global", player_id)
# Get top 100 players
top100 = redis.zrevrange("leaderboard:global", 0, 99, withscores=True)
# Get players near rank 1000 (rank 995-1005)
neighbors = redis.zrevrange("leaderboard:global", 994, 1004, withscores=True)
Scaling to 50 Million Players
A single Redis sorted set for 50M players uses approximately 3GB of memory (50M * 60 bytes per member). This fits on one Redis instance, but for write throughput during peak hours (millions of matches finishing simultaneously), shard the leaderboard by region or game mode, then compute global rank by merging regional top lists. For the global top-100, a secondary aggregation job runs every minute: pull top-1000 from each regional shard, merge and sort, write to a “global-top” Redis key that serves dashboard requests cheaply.
Tiered Leaderboards
Games typically have multiple leaderboard scopes: global, regional (North America, Europe, Asia), friends-only, seasonal (resets monthly). Friends leaderboard is the most personalized: store friend lists in Redis sets, then query scores for the specific player IDs in the friend set. Use ZSCORE to get each friend score in O(1), sort in application memory — efficient since friend lists are small (typically under 500).
Part 2: Skill-Based Matchmaking
Elo Rating System
Elo is the foundational skill rating system (used in chess, League of Legends, Overwatch). After each match: the winner gains points proportional to how unlikely their win was; the loser loses the same points. Expected win probability: E_A = 1 / (1 + 10^((R_B – R_A) / 400)). Points transferred: K * (actual – expected), where K is a scaling factor (32 for new players, 16 for experienced). High-rated players beating low-rated players gain almost nothing; upsets produce large rating swings. Modern games extend Elo with TrueSkill (accounts for team games and uncertainty) or Glicko-2 (adds rating reliability/deviation).
def update_elo(winner_rating, loser_rating, K=32):
expected_win = 1 / (1 + 10 ** ((loser_rating - winner_rating) / 400))
expected_loss = 1 - expected_win
new_winner = winner_rating + K * (1 - expected_win)
new_loser = loser_rating + K * (0 - expected_loss)
return round(new_winner), round(new_loser)
Matchmaking Queue Architecture
Players enter a matchmaking queue. The matchmaker must balance match quality (similar skill ratings) against wait time (do not keep players waiting more than 30 seconds). Architecture: (1) Players join a Redis sorted set keyed by queue entry time, with score = Elo rating. (2) A matchmaker service polls the queue every 500ms. (3) It groups players within a skill band: initially +/- 100 Elo, expanding by 25 every 5 seconds the player waits. (4) When a full lobby (10 players) is formed from the same skill band, a game server is provisioned. (5) Players are notified via WebSocket and sent the game server IP and session token.
Latency-Aware Server Selection
Skill alone is not enough — players on different continents get unacceptable ping if placed on the same server. Before forming a lobby, each player sends a ping to regional game server endpoints (US-East, US-West, EU, Asia). The matchmaker stores player-to-region latency as metadata alongside the queue entry. When grouping a lobby, the algorithm selects players where all members have under 60ms ping to at least one common region. If no region works within 30 seconds, the matchmaker relaxes to the region with minimum average latency across the group.
Game Server Lifecycle
Game servers are stateful and ephemeral. Use a server pool with pre-warmed instances to avoid cold start latency. When a match is ready: (1) The matchmaker requests a server from the fleet manager. (2) The fleet manager selects the least-loaded pre-warmed instance in the target region. (3) The game server receives player session tokens, validates them with the auth service, and begins the game. (4) During the match, game state is replicated to a standby server — if the primary crashes, the standby takes over with minimal interruption. (5) After the match, the server reports results to the scoring service, which updates Elo ratings and the leaderboard, then terminates.
Anti-Cheat Considerations
- Smurfing detection: new accounts with suspiciously high win rates trigger accelerated Elo placement
- Score integrity: match results are submitted by the authoritative game server, not the client
- Leaderboard fraud: rate-limit score updates per player per time window; audit anomalous score jumps
- All match results stored immutably in append-only event log for retroactive fraud investigation
Interview Tips
- Redis sorted set for leaderboard is the expected answer — know ZADD, ZRANK, ZREVRANGE complexity
- Matchmaking is a search problem: clarify acceptable wait time and quality tradeoff before designing
- Expanding search radius over time is the key insight — prevents starvation without sacrificing quality for quick matches
- Latency-aware matching differentiates a strong answer
- For Elo updates, emphasize atomicity — concurrent match results must not corrupt ratings
Frequently Asked Questions
How does a real-time leaderboard work at scale?
Real-time leaderboards use Redis sorted sets (ZSET). Each player ID is a member; their score is the numeric value. ZADD updates a score in O(log N). ZRANK returns rank in O(log N). ZREVRANGE returns the top-K players in O(log N + K). For 50 million players, a single sorted set uses about 3GB of memory and fits on one Redis instance. For global scale with millions of concurrent score updates, shard by region or game mode. A background aggregation job runs every 60 seconds: it reads the top-1000 from each regional shard, merges and sorts them, and writes the result to a global-top-100 key that serves all dashboard requests cheaply without touching the primary sorted sets.
How does skill-based matchmaking (SBMM) work?
SBMM queues players in a Redis sorted set scored by their skill rating (Elo, TrueSkill, or MMR). A matchmaker polls every 500ms and groups players within a skill band — initially narrow (+/- 100 Elo) to ensure fair matches, expanding by 25 Elo every 5 seconds to prevent starvation (no player waits more than 30-60 seconds). When a full lobby (e.g., 10 players for a battle royale) is assembled within the same skill band, the matchmaker also checks that all players have acceptable ping to at least one common game server region. If the skill or latency constraints cannot be satisfied together within the time limit, the system relaxes skill tolerance while keeping a hard latency cap, because high ping degrades game quality more visibly than a slight skill imbalance.
What is the Elo rating system and how is it calculated?
Elo is a method for calculating relative skill levels. After each match, points transfer from loser to winner proportional to how surprising the outcome was. Expected win probability for player A: E_A = 1 / (1 + 10^((R_B – R_A) / 400)). Points transferred: K * (actual_score – expected_score), where K is a constant (32 for new players, 16 for established). If a 2000-rated player beats a 1800-rated player, the 2000 player had an 88% expected win rate, so they gain only K * 0.12 = 3-4 points. If the 1800-rated player wins, they gain K * 0.88 = 28 points. This self-corrects: strong players in weak brackets rapidly accumulate points. Modern games use TrueSkill (Microsoft) for team games, which accounts for team composition and models uncertainty in addition to rating.
{ “@context”: “https://schema.org”, “@type”: “FAQPage”, “mainEntity”: [ { “@type”: “Question”, “name”: “How does a real-time leaderboard work at scale?”, “acceptedAnswer”: { “@type”: “Answer”, “text”: “Real-time leaderboards use Redis sorted sets (ZSET). Each player ID is a member; their score is the numeric value. ZADD updates a score in O(log N). ZRANK returns rank in O(log N). ZREVRANGE returns the top-K players in O(log N + K). For 50 million players, a single sorted set uses about 3GB of memory and fits on one Redis instance. For global scale with millions of concurrent score updates, shard by region or game mode. A background aggregation job runs every 60 seconds: it reads the top-1000 from each regional shard, merges and sorts them, and writes the result to a global-top-100 key that serves all dashboard requests cheaply without touching the primary sorted sets.” } }, { “@type”: “Question”, “name”: “How does skill-based matchmaking (SBMM) work?”, “acceptedAnswer”: { “@type”: “Answer”, “text”: “SBMM queues players in a Redis sorted set scored by their skill rating (Elo, TrueSkill, or MMR). A matchmaker polls every 500ms and groups players within a skill band — initially narrow (+/- 100 Elo) to ensure fair matches, expanding by 25 Elo every 5 seconds to prevent starvation (no player waits more than 30-60 seconds). When a full lobby (e.g., 10 players for a battle royale) is assembled within the same skill band, the matchmaker also checks that all players have acceptable ping to at least one common game server region. If the skill or latency constraints cannot be satisfied together within the time limit, the system relaxes skill tolerance while keeping a hard latency cap, because high ping degrades game quality more visibly than a slight skill imbalance.” } }, { “@type”: “Question”, “name”: “What is the Elo rating system and how is it calculated?”, “acceptedAnswer”: { “@type”: “Answer”, “text”: “Elo is a method for calculating relative skill levels. After each match, points transfer from loser to winner proportional to how surprising the outcome was. Expected win probability for player A: E_A = 1 / (1 + 10^((R_B – R_A) / 400)). Points transferred: K * (actual_score – expected_score), where K is a constant (32 for new players, 16 for established). If a 2000-rated player beats a 1800-rated player, the 2000 player had an 88% expected win rate, so they gain only K * 0.12 = 3-4 points. If the 1800-rated player wins, they gain K * 0.88 = 28 points. This self-corrects: strong players in weak brackets rapidly accumulate points. Modern games use TrueSkill (Microsoft) for team games, which accounts for team composition and models uncertainty in addition to rating.” } } ] }