Design a real-time gaming leaderboard
Design a real-time leaderboard for a mobile game. Players earn points by winning matches; the game shows the global top 10 and each player's own rank, and the leaderboard resets every month.
Practise it in the interview simulatorDraw your design on a canvas, stress test it with real traffic, and get a scored report. Or watch this answer build itself, step by step.1. Clarify the requirements
Before drawing anything, ask questions. These are the answers an interviewer would typically give:
- How many players?
- 25 million daily active players and 70 million who play at least once a month. Each plays about 10 matches a day.
- How real-time?
- A new score and rank should show up within a second or two.
- What's displayed?
- The top 10, plus the player's own rank with a few players above and below.
- Ties?
- Players with the same score: whoever reached it first ranks higher.
- Resets?
- Every month. Past months stay viewable.
- Who reports scores?
- The game server, never the client.
2. Estimate the scale
Assumptions: 25M DAU, 10 matches per player per day, half of them wins that add points. Each player opens the leaderboard 5 times a day. 70M monthly players; a sorted-set entry is about 100 bytes.
- Score updates per second: about 1447 updates/s25M × 10 × 50% ÷ 86,400 ≈ 1,450 updates/s.
- Leaderboard reads per second: about 1447 reads/s25M × 5 ÷ 86,400 ≈ 1,450 reads/s.
- Memory for one month's sorted set: about 7 GB70M players × 100 bytes = 7 GB: it fits on one Redis node.
3. The high-level design
- Players reach a trusted game serviceScores come from finished matches on the server, never straight from the client, so players can't post fake scores.
- Durable scoresMatch results and points are stored durably; the leaderboard can always be rebuilt from them.
- Rankings in a sorted setA Redis sorted set keeps players ordered by score: add points with ZINCRBY, read the top 10 with ZREVRANGE and a player's rank with ZREVRANK, all in O(log n).
- Watch it in productionMetrics and alerts close the loop: update latency and sorted-set memory.
4. The components and what each one does
- Load balancer Load balancer
- Spreads requests over the stateless servers behind it, health-checks them and routes around a dead one. Rate limits abusive clients.
- Game service App servers
- Trusted: scores come from finished matches on the server. Writes the score and updates the leaderboard.
- Scores & players SQL database
- Match history and points; sharded by player ID; primary + replicas with failover.
- Leaderboard (Redis sorted sets) Cache · Redis
- ZINCRBY on each win; ZREVRANGE for the top 10; ZREVRANK for a rank. One sorted set per month.
- Metrics & alerts Metrics & alerts
- Dashboards and alerts on p99 latency, error rate, queue depth and cache hit ratio, so a bottleneck shows up before it becomes an outage.
5. Deep dive: ranking millions of players fast
How do you return a player's exact rank among tens of millions in milliseconds, plus the top 10, while scores change thousands of times a second? What happens when it no longer fits on one machine?
- A relational ORDER BY over millions of rows on every request is far too slow, and a rank needs counting everyone above you.
- Redis sorted sets keep members ordered by score: ZINCRBY to update, ZREVRANK for a rank, ZREVRANGE for the top 10, all O(log n).
- Past one node: shard by score range (exact ranks: add the counts of higher shards) or by player ID (scatter-gather for the top 10).
6. What interviewers listen for
- Score and leaderboard APIsPOST /v1/scores (from the game server); GET /v1/leaderboard/top and GET /v1/leaderboard/rank/{playerId}.
- Sorted-set operations (ZINCRBY, ZREVRANK, ZREVRANGE)Name the data structure and its operations; they're what make ranks cheap.
- Recover the leaderboard if the cache is lostUse replicas and persistence, and be able to rebuild the sorted set from the database.
- Scaling past one node: shard by score range or playerScore-range shards keep ranks exact (add counts of higher shards); player-ID shards need scatter-gather for the top 10.
- Tie-breakingEncode time into the score so whoever got there first ranks higher.
- A new sorted set each monthUse one key per month (leaderboard:2026-10) and archive old ones; no mass deletes.
- Updates through a queue to absorb burstsA queue between match results and the leaderboard smooths spikes, like tournament finals.
- Database replication and failoverA single database is a single point of failure. Replicas give redundancy and read capacity; failover promotes a replica when the primary dies.
- Partition (shard) data as it growsOne machine eventually can't hold the data or the write load. Say how you'd split it and by which key.
7. Follow-up questions
- Why not keep scores in MySQL and run ORDER BY score DESC LIMIT 10?
- Your player base grows 20× and the sorted set no longer fits on one machine. How do you still show an exact rank?
- Someone shows up with a score of 999,999,999. How did it happen, and how do you stop it?
The key points for each follow-up, your scored report and the stress test are part of Pro: ₹299 a month or ₹1,999 a year.
See ProThe design in a nutshell
- Game servers → API (authenticated) → queue → leaderboard service → Redis sorted set leaderboard:<month> (ZINCRBY).
- Top 10 via ZREVRANGE 0 9 (cached for a second or two); a player's rank via ZREVRANK, with neighbours from ZREVRANGE around it.
- Match results and scores also stored in a durable database; Redis replicated with persistence and rebuildable from the database.
- Ties broken by encoding the time into the score; a fresh sorted set each month.
- Beyond one node: shard by score range and add the counts of higher shards to get exact ranks.
Related lessons: Where to cache, and how much it helps · Database scaling and sharding · Indexes: why lookups are fast (and writes slower)