logo

Overview

Source: Neo Kim — systemdesign.one
Real-time leaderboards are used in gaming, trading platforms, fitness apps, and hackathons. They must support millions of concurrent score updates while allowing instant rank queries — a challenging combination for any database.

Key Concepts

Sorted Set (Redis ZSET) — A Redis data structure that stores members with associated scores, automatically sorted. Supports O(log N) insertion/update and O(log N + K) rank queries. The core building block for real-time leaderboards.
Sharding — Distributing the leaderboard across multiple Redis nodes when the dataset exceeds single-node capacity.
Relative Rank — The position of a user among all participants (e.g., #1,423 out of 2M). Computing this exactly at scale requires counting all users with a higher score.

Functional Requirements

  • Update a user's score
  • Get a user's current rank
  • Get the top N users (global leaderboard)
  • Get users near a specific user's rank
  • Support for millions of concurrent users

Architecture

  • Score Update Service — Receives score update events (e.g., game completion). Writes to Redis ZSET and PostgreSQL.
  • Redis ZSET — Stores (userId, score) pairs sorted by score. Used for all rank queries.
  • PostgreSQL — Durable store for score history and user profile data.
  • Leaderboard API — Exposes endpoints for rank queries and top-N lists.
  • Cache Layer — Caches top-100 leaderboard snapshot (refreshed every 60s for global leaderboards).

Core Redis Operations

ZADD leaderboard <score> <userId> # Insert/update score: O(log N) ZRANK leaderboard <userId> # Get rank (0-indexed): O(log N) ZREVRANK leaderboard <userId> # Get rank from top: O(log N) ZREVRANGE leaderboard 0 99 # Top 100 users: O(log N + K) ZRANGEBYSCORE ... # Users in score range: O(log N + K)

Handling Scale

Single Redis node handles up to ~50M users comfortably (sorted set in memory).
Beyond single node — Sharding strategies:
Strategy
Approach
Score range sharding
Each shard owns a score range (e.g., 0–1000, 1001–2000)
Consistent hashing
Users distributed across shards by userId hash
Hierarchical
Local shards feed into a global aggregated leaderboard
Approximate rank for ultra-scale: Skip list or count-min sketch approximation for systems with billions of users where exact rank is unnecessary.

Score Update Flow

  1. Game server publishes score event to Kafka
  1. Score Update Service consumes event
  1. Updates Redis ZSET with new score
  1. Writes score update to PostgreSQL for durability
  1. If top-100 cache is invalidated, refresh job runs

Key Trade-offs

Decision
Reasoning
Redis ZSET over DB query
O(log N) vs. O(N) COUNT(*) query for rank
Kafka for score events
Decouples game servers from leaderboard service; absorbs spikes
Cached top-N
Global top-100 doesn't need real-time accuracy; 60s refresh acceptable
PostgreSQL for history
Redis data is ephemeral; durable store needed for audit/replay