Skip to main content
Articles/System Design/system-design-hld-leaderboard-example
Scenario Article

System Design HLD Example: Real-Time Leaderboard

Deep Dive: Why Redis Sorted Sets Achieve What SQL Cannot

Abstract Algorithms•Mar 28, 2026
💡 Executive Summary

Real-time leaderboards for 10M+ active users require an in-memory ranking engine.

🎯 System Scenario & Requirements

System Goal

Real-time leaderboards for 10M+ active users require an in-memory ranking engine.

Actors & Components

  • Architecture diagram in the source
  • Edge Traffic Ingress
  • Stateless Microservices
  • Datastore Infrastructure
  • API Gateway
  • Domain Service
  • Redis Cache
  • Transactional DB

Functional Requirements

  • TLDR: Real-time leaderboards for 10M+ active users require an in-memory ranking engine.
  • Redis Sorted Sets (ZSET) are the industry standard, providing $O(\log N)$ updates and rank lookups via an internal Skip List data structure.
  • Relational databases fail at this scale because calculating rank is an $O(N)$ operation (counting rows with higher scores) that becomes a bottleneck during peak traffic spikes.

Constraints & Assumptions

  • Critical Failure Mode — The Redis Restart Without Persistence: If the Redis instance restarts and AOF (Append Only File) persistence was not enabled, the entire ZSET is lost.
  • Re-hydrating 100M entries from Postgres requires streaming all score records, computing each player's cumulative score, and executing 100M ZADD commands.

⚡ Execution Stages & Decision Trace

1

Stage 1 — The Last-Minute Snipe

Action / Decision:

Imagine it’s the final minute of a week-long gaming tournament.

Component Behavior:

Ten million players are grinding for the top spot.

Observable Output: You’re currently ranked 10, and you just scored 5,000 points.
Read Full Stage in Deep Dive ↓
📖

Deep Dive

Detailed Architectural Analysis

Scenario context

Real-time leaderboards for 10M+ active users require an in-memory ranking engine. Redis Sorted Sets (ZSET) are the industry standard, providing $O(\log N)$ updates and rank lookups via an internal Skip List data structure. Relational databases fail at this scale because calculating rank is an $O(N)$ operation (counting rows with higher scores) that becomes a bottleneck during peak traffic spikes.


This walkthrough focuses on **Deep Dive: Why Redis Sorted Sets Achieve What SQL Cannot**.

Before making a design choice, clarify:

- The performance gulf between Redis ZSET and SQL for leaderboard rank queries is not a matter of hardware speed — it is a fundamental algorithmic difference.
- Understanding the internals of the Redis Skip List reveals why this gap exists and why no amount of database tuning closes it.
- Internals: The Skip List and Hash Map That Power ZREVRANK A Redis Sorted Set is implemented internally as two data structures working in tandem : 1.

**Concepts in play:** caching, system-design-hld-architectures, transaction-isolation-distributed-acid, database-indexing

## Stage 1 — The Last-Minute Snipe

- Imagine it’s the final minute of a week-long gaming tournament.
- Ten million players are grinding for the top spot.
- You’re currently ranked 10, and you just scored 5,000 points.
- You expect to see your rank jump to 2 immediately.

*Applies [**caching**](/concept/caching) to the decision above.*

**Observable outcome:** You expect to see your rank jump to 2 immediately.

## Stage 2 — Real-Time Leaderboard: Use Cases & Requirements

- Actors & Journeys - Player: Plays matches, earns points, and checks their global and friends-list ranking.
- - Game Server: The authoritative source that validates gameplay and submits the final score to the leaderboard service.
- - Tournament Admin: Configures seasons, resets scores, and monitors for cheating behavior.
- Functional Requirements - Score Submission: Update a player's score after a match.

*Applies [**system-design-hld-architectures**](/concept/system-design-hld-architectures) to the decision above.*

**Observable outcome:** Functional Requirements - Score Submission: Update a player's score after a match.

## Stage 3 — Basics: How Ranking Differs from Sorting

- At first glance, a leaderboard seems like a simple sorting problem.
- Just sort the table by score and pick the top rows.
- However, at scale, there is a massive difference between sorting and ranking .
- Sorting: Ordering a set of elements.

*Applies [**transaction-isolation-distributed-acid**](/concept/transaction-isolation-distributed-acid) to the decision above.*

**Observable outcome:** Sorting: Ordering a set of elements.

## Stage 4 — Mechanics: The Logic of Score Updates

- The core mechanic of a modern leaderboard is the Accumulation and Fan-out of score events.
- - Incremental Updates: Instead of overwriting the score, we often send "score deltas" (e.g., +50 points).
- This allows for easier concurrent updates.
- - Tie-Breaking: To ensure deterministic ranking, we use a composite score.

*Applies [**database-indexing**](/concept/database-indexing) to the decision above.*

**Observable outcome:** - Tie-Breaking: To ensure deterministic ranking, we use a composite score.

## Stage 5 — Estimations & Design Goals

- The Math of Massive Ranking - Total Players: 100 Million.
- - Daily Active Users (DAU): 10 Million.
- - Peak Write Throughput: 50,000 score updates/sec.
- - Peak Read Throughput: 100,000 rank queries/sec.

*Applies [**caching**](/concept/caching) to the decision above.*

**Observable outcome:** - Peak Read Throughput: 100,000 rank queries/sec.

## Stage 6 — High-Level Design: The Ranking Pipeline

- The architecture separates the fast-path ranking engine from the durable-path storage.
- The Ranking Pipeline above separates two concerns that must never share a bottleneck: the write path (score ingestion via Kafka → Score Processor → Redis ZSET) and the read path (Leaderboard API → Redis ZREVRANK).
- The Game Server never writes directly to Redis — it goes through the Ingestion Service and Kafka, ensuring durability before the score is considered committed.
- If Redis is unavailable, the API falls back to Postgres for correctness at the cost of higher latency.

*Applies [**system-design-hld-architectures**](/concept/system-design-hld-architectures) to the decision above.*

```architecture
{
  "version": 1,
  "title": "High-Level Design: The Ranking Pipeline - Subsystem Overview",
  "description": "Decoupled system architecture isolating ingress, stateless logic, and persistent datastores.",
  "view": "high-level",
  "pattern": "microservices",
  "direction": "LR",
  "groups": [
    { "id": "edge", "label": "Edge Traffic Ingress", "tone": "slate" },
    { "id": "services", "label": "Stateless Microservices", "tone": "blue" },
    { "id": "data", "label": "Datastore Infrastructure", "tone": "green" }
  ],
  "nodes": [
    { "id": "gw", "component": "api-gateway", "label": "API Gateway", "group": "edge", "badge": "TLS & Auth" },
    { "id": "app", "component": "workflow-service", "label": "Domain Service", "group": "services", "badge": "Stateless" },
    { "id": "cache", "component": "redis", "label": "Redis Cache", "group": "data", "badge": "Sub-ms Reads" },
    { "id": "db", "component": "postgres", "label": "Transactional DB", "group": "data", "badge": "ACID Log" }
  ],
  "edges": [
    { "from": "gw", "to": "app", "kind": "request", "label": "gRPC Request" },
    { "from": "app", "to": "cache", "kind": "read", "label": "Cache Lookups" },
    { "from": "app", "to": "db", "kind": "write", "label": "Durable Write" }
  ],
  "takeaway": {
    "title": "Architecture Boundary Invariant",
    "body": "Stateless compute nodes scale horizontally while shielding underlying database clusters behind fast cache layers."
  }
}
graph TD
    Game[Game Server] -->|Score| Ingest[Ingestion Service]
    Ingest -->|Kafka| MQ[Message Queue]
    MQ --> Processor[Score Processor]

    Processor -->|ZADD| Redis[(Redis ZSET Index)]
    Processor -->|Write| Postgres[(Postgres: Score History)]

    Player -->|Get Rank| API[Leaderboard API]
    API -->|ZREVRANK| Redis
    API -.->|Fallback| Postgres

Observable outcome: If Redis is unavailable, the API falls back to Postgres for correctness at the cost of higher latency.

End-to-end outcome

After working through the stages, you should be able to explain:

  • Lesson 1 — The composite score encoding must be documented prominently.
  • A developer joining the team months later will see a score like 892000001707868800 in Redis and have no idea it encodes both points and a timestamp.

Alternatives considered

The source focuses on one primary design. A second architecture is not compared, so no alternative is invented here.

Failure and degraded modes

In-Memory Speed vs. Durability: Trade-offs in Leaderboard Design

  • Detection: Critical Failure Mode — The Redis Restart Without Persistence: If the Redis instance restarts and AOF (Append Only File) persistence was not enabled, the entire ZSET is lost.
  • User or operator impact: Critical Failure Mode — The Redis Restart Without Persistence: If the Redis instance restarts and AOF (Append Only File) persistence was not enabled, the entire ZSET is lost.

Share this case study

Discuss architecture trade-offs and lessons with your team.

Share:XLinkedInReddit