DevOpsInterviews logo
← DevOps System Design & Architecture / 17
easyFlipkartPhonePeSwiggy

Design a real-time leaderboard for a mobile game with ten million daily players.

The vocabulary question hiding real depth: which primitive replaces ORDER BY, why sharding by player is wrong, and what a 45,000 updates-per-second storm actually costs.

Grounded in researched DevOps, SRE and platform engineering interview loops, written to a senior-engineer editorial bar, and never padded to hit a word count.

TL;DR: One Redis sorted set per game or season answers scores, global rank, and nearby players with O(logN) rank lookups and O(logN+M) range reads returningMmembers; shard by game, never by player, because rank is a property of the whole set. Pipelined updates absorb score storms, and cohort filters mark where this design stops.

How to approach it

Name the three query shapes first: submit a score, read the top 100, read a player's own rank and neighbours. Then size the write path, because update volume, not read volume, is what stresses this design.

A strong answer

Mechanics. A Redis sorted set does all three natively: ZINCRBY updates, ZREVRANGE 0 99 WITHSCORES for the podium, ZREVRANK for personal rank. Updates and rank lookups are O(log N); range reads additionally cost the number of returned members. Big-O does not establish a microsecond latency bound. The reason this primitive matters is what it replaces: a relational ORDER BY score DESC LIMIT 100 re-sorts or scans an index on every read, and a personal rank becomes a COUNT(*) WHERE score > mine, which is linear in the number of players above you. The sorted set maintains the ordering as a side effect of the write instead.

Capacity arithmetic. Ten million daily players submitting twenty score events each is 200 million updates a day, about 2,300 per second on average, peaking near 45,000 during a tournament final. Benchmark the real sorted-set size, member bytes, persistence and pipeline depth; a simple-command benchmark does not prove 45k updates/s capacity. Size memory including allocator/index overhead and a replica. Reads mostly go to replicas since leaderboards tolerate slightly stale ranks. One primary plus one replica is the honest footprint, and saying so beats inventing a cluster.

Details that separate practitioners:

  • Ties. Redis scores are double-precision numbers. If packing score and timestamp, prove the entire integer encoding stays within 2^53 and define range/overflow behavior; otherwise use an explicit bounded tie-break design or accept lexicographic member ordering for equal scores.
  • Seasons. Namespace keys per season (lb:s42), archive to the database at close, set TTLs. Un-namespaced boards grow into unmigratable monsters.
  • Durability. Scores are derivable only with replay-safe updates: deduplicate event IDs atomically with ZINCRBY, or apply authoritative versioned absolute scores. Replaying raw increments doubles points. AOF with every-second fsync is enough; losing a second of increments beats stalling writes.

Options compared:

ApproachGlobal rank queryUpdate costFits when
Redis sorted setExact, O(log N)O(log N)Real-time boards, seasons, neighbour views
SQL ORDER BY on indexed scoreExact, slows as N growsCheapLow traffic, heavy filtering needs
Precomputed buckets or percentilesApproximateBatchTens of millions of players, fuzzy rank acceptable

Where it stops working. Friends-only or city-filtered boards break the single-set model. Either maintain a sorted set per cohort and pay the fan-out write cost, or compute cohort ranks offline and accept staleness. Name that reversal yourself; the interviewer is waiting to ask.

What interviewers probe next

"A score storm doubles your peak. What breaks first?" The single-threaded primary saturating on command volume. Mitigate with pipelining, then read replicas; beyond one node, shard players into per-tier sets with periodic merges for approximate global ranks.

"Show me the players ranked just around me." ZREVRANK gives my position, then ZREVRANGE over a window around it fetches neighbours, with O(logN+M) work forMreturned neighbours.

"Redis restarts mid-tournament." Promotion timing and acknowledged-update loss depend on the failover and persistence configuration and the board rebuilds from the gameplay event stream; scores are derived data, so treat them that way.

Common mistakes

Sharding by player ID, then scattering every leaderboard view across all shards to re-rank, which puts scatter-gather on the hot path.

Keeping a rank column in SQL updated per play, rewriting thousands of rows on every score change.

Ignoring tie-breaking until players notice identical scores flipping order between refreshes.

References

Redis ZADD score precision.

That one was free, and so are 18 answers per topic without an account. Signing in doubles that to 28, keeps your bookmarks, and tracks which topics you keep getting wrong.one Google click · no card · nothing to cancel
HOW DID IT GO?
0
UP NEXT ON YOUR JOURNEY
NOTES & DISCUSSION · 0

Nothing here yet. Say how you would answer it.