Markdown Editor

Gaming Leaderboard System Design Template

Introductory: sorted sets, time-encoded tie breaking within 53 bits, top N and my rank, sharded ranks, friends boards, seasonal resets, anti-cheat boundary

सिस्टम डिज़ाइनपूर्णdesigngamingleaderboardmath
एडिटर में खोलें.md डाउनलोड करें

उपयोग कैसे करें: Use it when adding live rankings to a game or practising an introductory system design interview. Fill the ranking scope and the tie rule first, then the player count per board. The main pitfall is keeping scores only in the cache and accepting scores from game clients instead of trusted servers.

प्रीव्यू

System Design: [Gaming leaderboard name]

Reference design for a real-time gaming leaderboard: score updates from trusted game servers, ranking with in-memory sorted sets, deterministic tie breaking, "my rank" and "top N" queries, sharding when one set is not enough, friends leaderboards, seasonal resets, and the boundary with anti-cheat. It is an introductory design: it explains each building block before using it, so it suits a first system design review or interview practice. It follows the structure of the System Design Document template, adds a 45-minute interview path, access-pattern and failure-mode tables, and is pre-filled with a worked design to adapt. Replace every [bracketed] value and every row marked Example; values marked Example are assumptions, not benchmarks.

Document control

FieldValue
Document ID[SDD-LB-001]
System / feature[Real-time leaderboard]
Version[0.1]
Status[Draft / In review / Approved / Implemented / Superseded]
Owner[@owner]
Author(s)[@author]
Reviewers[@reviewer-1], [@reviewer-2]
Last updatedYYYY-MM-DD
Classification[Internal]
DifficultyIntroductory
Games and modes covered[Game titles, modes, regions]
Related[Match service design], [Anti-cheat policy], [ADR: tie rule]

Approvals

RoleNameDecisionDate
Tech lead[@name][Approved / Changes requested]YYYY-MM-DD
Game design (ranking rules)[@name][Decision]YYYY-MM-DD
SRE / operations[@name][Decision]YYYY-MM-DD
Trust and safety (anti-cheat)[@name][Decision]YYYY-MM-DD

Revision history

VersionDateAuthorChange summary
0.1YYYY-MM-DD[@name]First draft for design review
0.2YYYY-MM-DD[@name]Example: Encoded time into the score to break ties by first to reach
0.3YYYY-MM-DD[@name]Example: Added friends leaderboard computed at read time
1.0YYYY-MM-DD[@name]Example: Approved

Contents

1. Overview

1.1 Problem statement

[Example: The game computes rankings with a nightly SQL job that sorts all players by points. Players see yesterday's rank, the "top 100" page times out during events, and two players with equal points swap places between page loads. The new season mode needs live ranks for 50 million players.]

1.2 Proposed solution

[Example: When a match ends, the match service (a trusted server, not the game client) publishes a signed score event. A leaderboard writer records the event durably in a database and updates an in-memory sorted set for the current season. Ranks and the top 100 are read from the sorted set in a few milliseconds. Ties are broken by who reached the score first, encoded inside the sorted-set score. Friends leaderboards are computed at read time from the friend list. Each season uses a new key, so a reset is a key switch, not a mass delete.]

1.3 Decisions requested from reviewers

IDQuestionRecommended optionSection
Q-01Example: Database ORDER BY or in-memory sorted set?Sorted set, database as source of truth7.1, 10
Q-02Example: How are ties broken?First to reach the score ranks higher7.2
Q-03Example: Shard now or later?One primary with replicas now; shard plan ready7.3
Q-04Example: Who can submit scores?Only the match service, with signed events7.6
[Q-nn][Question][Option][Section]

1.4 45-minute interview path

Use this order when the document serves an interview or a short review.

MinutesCoverOutput on the whiteboard
0 to 5Scope: update score, top N, my rank, friends; season reset; below-the-line itemsFour operations
5 to 10Estimates: updates per second, players per board, memoryThree numbers, "fits in one node" consequence
10 to 15API: submit score (server only), get top, get my rank with neighboursThree calls
15 to 25High-level design: match service, writer, database, sorted set, read APIOne diagram
25 to 40One deep dive: why a database sort fails and how a sorted set works (default), or ties, or shardingOptions, choice, reason
40 to 45Failures (cache lost, cheating), 10x changeFailure rows

Start the deep dive with the naive answer, a database query that counts rows with a higher score, and show why it gets slower as players grow. Then introduce the sorted set and its logarithmic rank lookup.

2. Requirements

2.1 Core functional requirements

IDRequirementPriority
FR-01Example: Add points to a player's season score when a match endsMust
FR-02Example: Show the top 100 players of the seasonMust
FR-03Example: Show a player's rank and the 5 players above and belowMust
FR-04Example: Break ties deterministically: first to reach the score ranks higherMust
FR-05Example: Start a new season monthly, keep past seasons readableMust
FR-06Example: Show a leaderboard of the player's friendsShould
FR-07Example: Remove a banned player and restore ranksMust
[FR-nn][Requirement][Must / Should / Could]

2.2 Non-functional requirements

IDQualityTargetMeasured as
NFR-01Read latencyExample: p99 at or below 50 ms for top 100 and my rankAPI timing
NFR-02FreshnessExample: New score reflected in rank within 2 s of match endEvent timestamp to read
NFR-03DurabilityExample: No accepted score lost, even if the cache is lostRebuild drill
NFR-04AvailabilityExample: 99.9% for reads; writes may queue during incidentsProbes
NFR-05CorrectnessExample: Same rank shown to every viewer at the same momentConsistency test
[NFR-nn][Quality][Target][Measurement]

2.3 Below the line (out of scope)

  • [Example: matchmaking ratings such as Elo or Glicko (a separate service; the leaderboard can display them)]
  • [Example: cheat detection itself (anti-cheat system; see 7.6 for the boundary)]
  • [Example: rewards and prize payout at season end]
  • [Example: cross-game global rankings]
  • [Item deferred, with the release that will take it]

3. Capacity estimation

3.1 Assumptions

InputSymbolValueSource
Daily active playersUUExample: 25 millionAnalytics
Matches per player per daymmExample: 10Analytics
Leaderboard views per player per dayvvExample: 20Client telemetry
Players in one season boardPPExample: 50 millionMonthly actives
Memory per sorted-set entry including overheadeeExample: 100 bytesMeasured with 16-byte ids
Peak to average ratio (events, weekends)kkExample: 5Traffic history
Simple operations one cache node serves per secondccExample: 100 000Benchmark on target instance

3.2 Score updates

W=U×m86 400=2.5×10886 400≈2 900 updates/s,Wpeak≈5×2 900=14 500 updates/sW = \frac{U \times m}{86\,400} = \frac{2.5 \times 10^{8}}{86\,400} \approx 2\,900 \ \text{updates/s}, \qquad W_{peak} \approx 5 \times 2\,900 = 14\,500 \ \text{updates/s}

Consequence: the write rate is far below what one in-memory node handles, so sharding is not needed for writes. Writes go through a queue only to absorb spikes and to make retries safe.

3.3 Reads

R=U×v86 400=5×10886 400≈5 800 reads/s,Rpeak≈29 000 reads/sR = \frac{U \times v}{86\,400} = \frac{5 \times 10^{8}}{86\,400} \approx 5\,800 \ \text{reads/s}, \qquad R_{peak} \approx 29\,000 \ \text{reads/s}

The top 100 is the same for everyone, so it is cached in the API for 1 s. "My rank" is per player and goes to the sorted set. Consequence: about 14 500+29 000≈44 00014\,500 + 29\,000 \approx 44\,000 operations per second at peak, under half of one node's Example capacity cc; read replicas add headroom and availability.

3.4 Memory

M=P×e=5×107×100 B=5 GB per season boardM = P \times e = 5 \times 10^{7} \times 100 \ \text{B} = 5 \ \text{GB per season board}

Consequence: the current season fits on one node with room to spare. Past seasons move to the database and are not kept in memory.

3.5 Summary

QuantityEstimateDesign consequence
Score updates~14 500/s at peakOne primary; queue for spikes and retries
Reads~29 000/s at peakCache top 100 for 1 s; replicas for my-rank
Memory~5 GB per season boardOne node; shard only for much larger boards (7.3)
DurabilityCache can be lostDatabase is the source of truth; rebuild job

4. API design

4.1 Endpoints

InterfaceOperationCallerPurpose
Internal eventScoreAwarded{match_id, player_id, points, season, ts, signature}Match service onlyAdd points
Public APIGET /v1/leaderboards/{board}/top?limit=100ClientTop N
Public APIGET /v1/leaderboards/{board}/players/{player_id}?around=5ClientRank and neighbours
Public APIGET /v1/leaderboards/{board}/friendsClient (signed in)Friends ranking
AdminPOST /v1/leaderboards/{board}/players/{player_id}/removeTrust and safetyRemove a banned player

4.2 Request and response examples

A rank request for one player with neighbours, and the response:

GET /v1/leaderboards/season-2026-10/players/p_8812?around=2 HTTP/1.1
{"board": "season-2026-10", "player": {"player_id": "p_8812", "rank": 1042, "points": 18350}, "neighbours": [{"rank": 1040, "player_id": "p_1201", "points": 18360}, {"rank": 1041, "player_id": "p_5530", "points": 18350}, {"rank": 1043, "player_id": "p_0077", "points": 18340}, {"rank": 1044, "player_id": "p_3109", "points": 18335}], "as_of": "2026-10-22T09:30:01Z"}

Players p_5530 and p_8812 both have 18 350 points; p_5530 reached it first, so it ranks higher (7.2).

4.3 Errors and idempotency

CaseStatusBody type
Unknown board or season404problems/unknown-board
Player has no score this season200 with rank: nullNot an error
Score event with bad signatureRejected, logged for trust and safetyNot visible to clients
Too many requests429 with Retry-Afterproblems/rate-limited

Score events carry match_id. The writer records (season, match_id, player_id) with a unique constraint, so a replayed event adds points once.

5. Data model

5.1 Entities

The database holds durable records; the sorted set is a derived index.

5.2 Storage choices

DataStoreKeyWhy
Score eventsExample: Relational database, partitioned by season(season_id, match_id, player_id)Idempotency and audit
Player totalsSame database(season_id, player_id)Source for rebuild and season archive
Live rankingExample: Redis sorted setlb:{game}:{season}Rank and range in logarithmic time
Final standingsDatabase table per season(season_id, final_rank)Past seasons without memory cost
Friend listsSocial serviceplayer_idOwned elsewhere, read at query time

5.3 Access patterns

QueryKey or index that serves itPartition key and rationale
Top 100 of the seasonZRANGE lb:{game}:{season} 0 99 REVBoard key; one board fits one node
My rankZREVRANK on the board key with the player idSame board key
Players around meZRANGE ... REV from rank minus 5 to rank plus 5Same board key
Friends rankingZMSCORE for up to a few hundred friend ids, sort in the APIBoard key; friends are a small set read at query time
Rebuild after lossScan PLAYER_SCORE by season_idSeason partition; sequential read
Past season rankFINAL_STANDING by (season_id, player_id)Season partition; cold data

6. High-level design

ComponentResponsibilityScales by
Match serviceDecide results and points on the serverGame fleet
Score event queueBuffer spikes, retry safelyPartitions by player id
Leaderboard writerVerify signature, record event, update totals and sorted setInstances, one partition each
Sorted set primary and replicasRank and range queriesReplicas; shards in 7.3
Leaderboard APIRead paths, top-N cache, friends mergeStateless instances
Rebuild jobRecreate the sorted set from the databaseOn demand

7. Detailed design

7.1 Deep dive: why a sorted set

To find a player's rank, something must know how many players have a higher score.

OptionTop NMy rankProblem
Database ORDER BY points DESC LIMIT 100Fast with an indexCOUNT(*) WHERE points > mine scans many index entriesRank cost grows with the number of players above you
Batch job that writes ranks nightlyFastFastHours old
In-memory sorted set (skip list plus hash map)LogarithmicLogarithmicMemory bound; needs a durable source

A sorted set keeps members ordered by a numeric score. Adding or updating a member and looking up its rank both take time proportional to the logarithm of the set size, so 50 million players cost only a few dozen steps. In Redis the commands are ZADD or ZINCRBY to write, ZREVRANK for rank from the top, and ZRANGE ... REV for a slice by rank (ZREVRANGE is deprecated since Redis 6.2).

Choice: a sorted set per board, with the database as the source of truth. Reason: it is the only option that serves both top N and my rank in milliseconds for a live board.

The writer writes the absolute total computed by the database rather than incrementing in the cache. A retried write then sets the same value again instead of adding points twice.

7.2 Deep dive: ties

When scores are equal, Redis orders members by their names byte by byte (reversed for the ZREV commands). The order of two tied players then depends on their ids, which is not a game rule.

OptionRuleCost
Accept lexicographic orderArbitrary but stablePlayers see unfair order
Shared rank ("both are 1041st")Equal scores share a rankRank query must count distinct higher scores; more work
Encode time in the scoreEarlier achiever ranks higherScore range must fit the encoding

Choice: encode time. Redis scores are double-precision numbers, which represent integers exactly only up to 2532^{53}. Split those 53 bits into points and time: with tt the whole seconds since the season started,

composite=points×222+(222−1−t)\text{composite} = \text{points} \times 2^{22} + \left(2^{22} - 1 - t\right)

2222^{22} seconds is about 48.5 days, enough for a monthly season, which leaves 31 bits for points (up to about 2.1 billion). Earlier tt gives a larger composite, so the earlier achiever ranks higher. The API decodes points as ⌊composite/222⌋\lfloor \text{composite} / 2^{22} \rfloor. Reason: it keeps every query a single sorted-set call. Players who reach the same score in the same second still fall back to id order; document that as the final rule.

7.3 Deep dive: sharding and top N

Sharding is not needed at the estimated size (3.5), but plan it for boards that outgrow one node, for example a global all-time board.

OptionTop NMy rankRisk
Shard by player id hash into KK setsRead top N from each shard, merge K×NK \times N results1+∑kZCOUNTk(score>s)1 + \sum_{k} \text{ZCOUNT}_k(\text{score} > s) across all shardsRank needs KK calls
Shard by score range (buckets)Read the highest bucketSizes of higher buckets plus rank inside own bucketHot top bucket; players move between shards
Exact rank for the top only, percentile for the restExact for top 10 000"Top 3%" from a score histogramApproximate for most players

Choice: hash sharding when needed, plus percentile display below the top 10 000. Reason: hash sharding keeps load even and top N is a cheap merge; players outside the top rarely need an exact six-digit rank, and a histogram answers "top 3%" with one lookup.

7.4 Friends leaderboards

OptionHowCost
Fan out on writeUpdate a sorted set per friend on every scoreEach update writes hundreds of sets
Compute on readFetch friend ids, read their scores with one multi-get, sort in the APIOne social call plus one cache call per view

Choose compute on read: friend lists are small (cap at Example 500), and friends boards are viewed far less often than scores change. Cache the result per player for Example 10 s.

7.5 Seasons and resets

Each season has its own key, for example lb:{game}:2026-10. At the season boundary (defined in UTC), the writer switches to the new key; the old set stays read-only for Example 7 days for late disputes, then a job writes FINAL_STANDING and deletes the old key. No mass delete happens at midnight, and late events for the old season are rejected by the season check. All-time boards, if any, are separate keys updated in parallel.

7.6 Anti-cheat boundary

The leaderboard is not where cheating is detected, but its design can make cheating harder:

  • Accept scores only from the match service, never from game clients, and verify an event signature or service identity.
  • Reject events outside plausible ranges (for example more points than a match can award) and route them to review.
  • Support removal: the anti-cheat system calls the admin API, the writer marks the player removed in the database and removes the member from the sorted set; ranks of everyone below change immediately.
  • Keep every score event, so points can be recomputed after a rules change or an exploit.

7.7 How real systems do it

How real systems do it (paraphrased, not copied). The AWS Database Blog post "Build a real-time gaming leaderboard with Amazon ElastiCache for Redis" (2019, updated 2024) describes moving ranking out of a relational database into Redis sorted sets, so that each score write keeps the set ordered and rank queries no longer scan tables. A later AWS for Games post on Amazon MemoryDB discusses the durability gap of a cache-only leaderboard and the common pairing of an in-memory store with a persistent database, which is the split used in this design. The Redis documentation itself lists leaderboards as a typical use of sorted sets and states that equal scores are ordered lexicographically, which is why 7.2 exists. Read the originals in 12.3; this box keeps only the general idea.

8. Scalability and performance

ConcernApproachLimit before redesign
Score writesOne primary, queue in frontExample: about 50% of node capacity
Top-N reads1 s cache in the APINone in practice
My-rank readsRead replicasReplica lag above NFR-02
Board sizeOne node per boardExample: above 30 GB, shard by player hash (7.3)
Events (launch day)Queue absorbs bursts; writer scales with partitionsQueue lag above 2 s

Latency budget for "my rank with neighbours" (target p99 50 ms):

StepBudget
API, auth10 ms
ZREVRANK on a replica2 ms
ZRANGE ... REV for neighbours2 ms
Profile names for 11 players (cached)10 ms
Network and headroom26 ms

9. Reliability, security and operations

9.1 Failure modes

ComponentFailureDetectionBlast radiusMitigationRTO
Sorted set primaryNode lostHealth checkWrites for the board pausePromote replica; replay recent events from the queueExample: 1 min
Sorted set dataLost or corruptedCount check against databaseBoard shows wrong ranksRebuild job from PLAYER_SCOREExample: 15 min for 50 million entries
WriterCrashes mid-batchQueue lagFreshness onlyIdempotent events, absolute totalsExample: 1 min
DatabasePrimary failoverError rateWrites queue; reads unaffectedQueue holds events until it returnsExample: 5 min
Season switchWrong boundary or timezoneEvents rejected spikeOne season's scoresUTC boundary in config, rehearsed in stagingExample: 30 min
ExploitInflated scoresAnti-cheat signals, outlier alertsTop of the boardRemove, recompute from eventsExample: 1 h
[Component][Failure][Signal][Scope][Mitigation][Time]

9.2 Security and privacy

ThreatControl
Client submits its own scoreNo public write endpoint; only the match service publishes events
Forged events on the queueSigned events or authenticated producer identity
Scraping of player listsRate limits; public names only, no account ids
Display of minors' namesShow display names chosen under the game's child safety rules
Abuse in display namesName moderation before a player can appear in public boards
[Threat][Control]

9.3 Observability

SignalMetricAlert threshold
FreshnessMatch end to rank update, p99Above 2 s for 10 min
ConsistencySorted-set size vs database countDifference above 0.01%
Read latencyp99 per endpointAbove 50 ms
Suspicious scoresPoints per match above the game maximumAny

9.4 Cost estimate

ItemUnit costQuantityMonthly cost
Cache nodes (primary and 2 replicas)[USD per node-month]3[USD]
Database[USD per month]1 cluster[USD]
Queue[USD per month][Partitions][USD]
Total[USD]

10. Trade-offs and alternatives

DecisionOptionsChosenWhyWhat we give up
Ranking storeDatabase sort; batch; sorted setSorted set plus databaseLive ranks in millisecondsTwo stores to keep in sync
Tie ruleLexicographic; shared rank; time encodedTime encodedFair, one call per queryScore range limited to 31 bits of points
Write styleIncrement in cache; set absolute totalAbsolute total from databaseRetries are safeDatabase on the write path
Friends boardFan out on write; compute on readCompute on readSmall lists, rare viewsExtra call per view
Season resetDelete members; new keyNew keyInstant, no mass deleteOld keys to clean up
What changes at 10x / 0.1x10x players: shard by player hash and show percentiles below the top. 0.1x: a database index with a 10 s cached top N is enoughReview per game launchSize moves the cache from optional to required[Note]
[Decision][Options][Chosen][Why][Cost]

11. Delivery plan and risks

11.1 Milestones

MilestoneScopeExit criterionTarget date
M1Writer, database, sorted set, top 100Load test at 2 times peakYYYY-MM-DD
M2My rank, neighbours, tie ruleTie tests passYYYY-MM-DD
M3Seasons and archiveSeason switch rehearsedYYYY-MM-DD
M4Friends board, removal flowRemoval reflected within 2 sYYYY-MM-DD

11.2 Rollout and rollback

[Example: Run the new leaderboard in shadow for one week, comparing ranks with the nightly job for a sample of players. Switch the client to the new API behind a flag; rollback switches the flag back to the nightly ranks.]

11.3 Risks

IDRiskLikelihoodImpactMitigationOwner
R-01Example: Points exceed 31 bits after a scoring changeLowHighValidate in the writer; widen time unit or shorten season[@name]
R-02Example: Players dispute tie orderMediumLowPublish the rule in game help[@name]
R-03Example: Exploit floods the top before detectionMediumHighPlausibility limits, fast removal tool[@name]
[R-nn][Risk][L / M / H][L / M / H][Mitigation][@name]

12. Appendices

12.1 Open questions

IDQuestionOwnerDue
OQ-01Example: Regional boards as separate keys or filtered views?[@name]YYYY-MM-DD
OQ-02Example: Do removed players keep their final standing record?[@name]YYYY-MM-DD
[OQ-nn][Question][@name]YYYY-MM-DD

12.2 Glossary

TermMeaning
Sorted setA collection of unique members ordered by a numeric score
RankPosition of a player counted from the top, starting at 1 in the UI
Composite scorePoints and time packed into one number so ties sort correctly
SeasonA time-boxed competition with its own board
Percentile rankShare of players with a lower score, shown instead of an exact rank

12.3 References

ReferenceUse
Redis documentation, "Redis sorted sets" (redis.io)7.1 commands, 7.2 lexicographic tie order
Tan, "Build a real-time gaming leaderboard with Amazon ElastiCache for Redis", AWS Database Blog, 2019 (updated 2024)7.7
Ishii, "Rethinking Game Leaderboards with Amazon MemoryDB for Redis", AWS for Games Blog, 20227.7 durability discussion
MDN Web Docs, Number.MAX_SAFE_INTEGER7.2 exact integers up to 2 to the power 53
Xu and Lam, System Design Interview: An Insider's Guide, Volume 2 (2022), chapter "Real-time Gaming Leaderboard"Inspiration only; no text or figures reused
Distributed Key-Value Store System Design (system-design/design-distributed-kv-store)Replication background
Back-of-Envelope Estimation and Capacity Model (system-design/back-of-envelope-estimation)Method for section 3

Standard and licence note

Based on common industry practice for real-time ranking and on the public documentation cited in 12.3. The book and engineering write-ups listed there are inspiration only; no text, diagrams or numbers were copied, and all figures here are illustrative examples. Check the current documentation of your cache and database for command behaviour and limits. Original text written for this collection. Template licence: MIT.

संबंधित टेम्पलेट