Introduction
A real-time game leaderboard is a critical component of gaming systems that displays player rankings based on scores, achievements, or other metrics. Designing a leaderboard system requires handling high write throughput (score updates), low latency reads, real-time updates, and multiple leaderboard types (global, friends, weekly, etc.).
This post provides a detailed walkthrough of designing a real-time game leaderboard system, covering key architectural decisions, ranking algorithms, data structures, and scalability challenges. This is a common system design interview question that tests your understanding of distributed systems, caching, real-time processing, and efficient data structures for ranking.
Table of Contents
- Problem Statement
- Requirements
- Capacity Estimation
- Core Entities
- API
- Data Flow
- Database Design
- High-Level Design
- Deep Dive
- Summary
Problem Statement
Design a real-time game leaderboard system with the following features:
- Players can submit scores after completing a game
- System maintains multiple leaderboards:
- Global leaderboard (all players)
- Friends leaderboard (player’s friends only)
- Weekly leaderboard (resets weekly)
- Country/Region leaderboard
- Players can view their rank and nearby players
- Leaderboard updates in real-time as scores are submitted
- Support for multiple game modes/types
- Historical leaderboard data (past weeks/months)
Scale Requirements:
- 100 million+ registered players
- 10 million+ daily active players
- 50 million+ score submissions per day
- 500 million+ leaderboard views per day
- Peak: 100,000 score submissions per second
- Read:Write ratio: 10:1 (500M views / 50M submissions)
- Average latency: < 50ms for reads, < 100ms for writes
Requirements
Functional Requirements
Core Features:
- Score Submission: Players submit scores after game completion
- Ranking: Calculate and maintain player ranks
- Multiple Leaderboards: Support different leaderboard types
- Real-time Updates: Leaderboard updates within seconds
- Rank Queries: Get player rank, top N players, players around rank
- Historical Data: Store and query past leaderboards
Out of Scope:
- Game logic and gameplay mechanics
- Player authentication (assume handled elsewhere)
- Payment processing
- Anti-cheat mechanisms (focus on system design)
Non-Functional Requirements
- Availability: 99.9% uptime
- Performance:
- Score submission: < 100ms (p95)
- Leaderboard read: < 50ms (p95)
- Real-time update latency: < 1 second
- Scalability: Handle 100K+ writes/second peak
- Consistency: Eventually consistent is acceptable
- Durability: All scores must be persisted
- Accuracy: Rankings must be accurate (no data loss)
Capacity Estimation
Traffic Estimates
- Daily Active Players (DAU): 10 million
- Daily score submissions: 50 million
- Daily leaderboard views: 500 million
- Read:Write ratio: 10:1
- Peak writes: 100,000 per second
- Peak reads: 1,000,000 per second
Storage Estimates
Score Records:
- 50M submissions/day × 200 bytes = 10GB/day
- 1 year retention: 10GB × 365 = 3.65TB
Leaderboard Data:
- 100M players × 100 bytes (rank metadata) = 10GB
- Multiple leaderboards (4x): 40GB
- With replication (3x): 120GB
Historical Data:
- Weekly snapshots: 52 weeks × 40GB = 2TB
- Monthly snapshots: 12 months × 40GB = 480GB
- Total historical: ~2.5TB
Total Storage: ~6TB
Bandwidth Estimates
- Write bandwidth: 50M submissions/day × 200 bytes = 10GB/day = 116KB/s
- Read bandwidth: 500M views/day × 5KB avg = 2.5TB/day = 29GB/s
- Peak bandwidth: 3x average = 87GB/s
Core Entities
Player
- Attributes: user_id, username, country_code, created_at, updated_at
- Relationships: Submits scores, has friends, participates in leaderboards
Score
- Attributes: score_id, user_id, game_id, leaderboard_type, score, metadata, created_at
- Relationships: Belongs to player and game, contributes to leaderboard ranking
Leaderboard
- Attributes: leaderboard_type, game_id, snapshot_date (for historical)
- Relationships: Contains scores, ranked by score value
Friend
- Attributes: user_id, friend_id, created_at
- Relationships: Links players for friends leaderboard
API
1. Submit Score
POST /api/v1/scores
Parameters:
- user_id: player ID
- game_id: game/mode ID
- score: score value
- leaderboard_type: "global", "weekly", "country", etc.
- metadata: optional (level, time, etc.)
Response:
- success: boolean
- rank: new rank
- previous_rank: previous rank (if applicable)
2. Get Leaderboard
GET /api/v1/leaderboard/{type}
Parameters:
- type: "global", "friends", "weekly", "country"
- limit: number of players to return (default: 100)
- offset: pagination offset (optional)
Response:
- players: array of player objects (rank, user_id, score)
- total_players: total number of players
3. Get Player Rank
GET /api/v1/leaderboard/{type}/rank/{user_id}
Parameters:
- type: leaderboard type
- user_id: player ID
Response:
- rank: player rank
- score: player score
- total_players: total players in leaderboard
4. Get Players Around Rank
GET /api/v1/leaderboard/{type}/around/{user_id}
Parameters:
- type: leaderboard type
- user_id: player ID
- range: number of players above/below (default: 5)
Response:
- players: array of players around the specified player
- player_rank: rank of the specified player
5. Get Historical Leaderboard
GET /api/v1/leaderboard/{type}/historical/{date}
Parameters:
- type: leaderboard type
- date: date in YYYY-MM-DD format
Response:
- players: array of players from historical leaderboard
- date: leaderboard date
Data Flow
Score Submission Flow
- Player submits score → Load Balancer
- Load Balancer → API Gateway
- API Gateway → Score Service
- Score Service validates score
- Score Service → Database (store score)
- Score Service → Message Queue (for async ranking)
- Message Queue → Ranking Engine (calculate rank)
- Ranking Engine → Redis (update leaderboard)
- Ranking Engine → Cache invalidation
- Response returned to client (with new rank)
Leaderboard Query Flow
- Client requests leaderboard → Load Balancer
- Load Balancer → API Gateway
- API Gateway → Leaderboard Service
- Leaderboard Service checks Redis cache
- If cache miss:
- Query Redis Sorted Set for leaderboard
- If not in Redis, query Database
- Cache result in Redis
- Return leaderboard to client
Rank Update Flow
- Score update triggers ranking recalculation
- Ranking Engine calculates new rank
- Ranking Engine updates Redis Sorted Set
- Ranking Engine → Message Queue (for real-time updates)
- Message Queue → Real-time Service
- Real-time Service pushes update to active clients via WebSocket
Database Design
Schema Design
Players Table:
CREATE TABLE players (
user_id BIGINT PRIMARY KEY,
username VARCHAR(255) NOT NULL,
country_code VARCHAR(2),
created_at TIMESTAMP,
updated_at TIMESTAMP,
INDEX idx_country (country_code)
);
Scores Table:
CREATE TABLE scores (
score_id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
game_id INT NOT NULL,
leaderboard_type VARCHAR(50) NOT NULL,
score INT NOT NULL,
metadata JSON,
created_at TIMESTAMP,
INDEX idx_user_game (user_id, game_id),
INDEX idx_type_score (leaderboard_type, score DESC),
INDEX idx_created (created_at),
FOREIGN KEY (user_id) REFERENCES players(user_id)
);
Leaderboard Snapshots Table:
CREATE TABLE leaderboard_snapshots (
snapshot_id BIGINT PRIMARY KEY AUTO_INCREMENT,
leaderboard_type VARCHAR(50) NOT NULL,
snapshot_date DATE NOT NULL,
snapshot_data JSON NOT NULL,
created_at TIMESTAMP,
UNIQUE KEY unique_snapshot (leaderboard_type, snapshot_date),
INDEX idx_type_date (leaderboard_type, snapshot_date)
);
Friends Table:
CREATE TABLE friends (
user_id BIGINT NOT NULL,
friend_id BIGINT NOT NULL,
created_at TIMESTAMP,
PRIMARY KEY (user_id, friend_id),
INDEX idx_user (user_id),
INDEX idx_friend (friend_id),
FOREIGN KEY (user_id) REFERENCES players(user_id),
FOREIGN KEY (friend_id) REFERENCES players(user_id)
);
Database Sharding Strategy
Shard by User ID:
- Player data, scores, friends on same shard
- Enables efficient player queries
Challenges:
- Global leaderboard requires aggregation across shards
- Need efficient cross-shard queries
High-Level Design
┌─────────────┐
│ Client │
│ (Game) │
└──────┬──────┘
│
▼
┌─────────────────────────────────────────┐
│ Load Balancer │
└──────┬──────────────────┬───────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Score │ │ Leaderboard │
│ Service │ │ Service │
└──────┬───────┘ └──────┬───────┘
│ │
├──────────────────┼──────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Ranking │ │ Cache │ │ Database │
│ Engine │ │ (Redis) │ │ (Sharded) │
└──────────────┘ └──────────────┘ └──────────────┘
Deep Dive
Component Design
1. Score Service
Responsibilities:
- Receive score submissions
- Validate scores
- Store scores in database
- Trigger ranking updates
Flow:
- Receive score submission
- Validate score (anti-cheat checks, etc.)
- Store score in database
- Publish to message queue for ranking
- Return acknowledgment
Optimizations:
- Batch writes for high throughput
- Async processing for ranking
- Rate limiting per user
2. Ranking Engine
Responsibilities:
- Calculate and maintain rankings
- Update leaderboard caches
- Handle tie-breaking logic
Data Structures:
Option 1: Redis Sorted Sets (Recommended)
Key: leaderboard:{type}:{game_id}
Type: Sorted Set
Score: score value
Value: user_id
Advantages:
- O(log N) insertion and update
- O(log N + M) range queries (top N)
- Built-in ranking operations
- Atomic operations
Operations:
ZADD: Add/update scoreZREVRANGE: Get top N playersZREVRANK: Get player rankZREVRANGEBYSCORE: Get players around rank
Option 2: Database with Materialized View
- Pre-computed rankings
- Slower updates but faster reads
- Good for less frequent updates
Ranking Algorithm:
Tie-breaking Logic:
- Higher score wins
- If scores equal, earlier submission wins (timestamp)
- If still equal, lower user_id wins (deterministic)
Score Calculation:
final_score = base_score + bonus_points - penalty_points
3. Leaderboard Service
Responsibilities:
- Serve leaderboard queries
- Handle pagination
- Cache frequently accessed data
Query Patterns:
Get Top N Players:
ZREVRANGE leaderboard:global:1 0 99 WITHSCORES
Get Player Rank:
ZREVRANK leaderboard:global:1 {user_id}
ZSCORE leaderboard:global:1 {user_id}
Get Players Around Rank:
rank = ZREVRANK leaderboard:global:1 {user_id}
ZREVRANGE leaderboard:global:1 rank-5 rank+5 WITHSCORES
Caching Strategy:
- Cache top 1000 players for each leaderboard
- TTL: 1 second (very short for real-time)
- Invalidate on score updates
4. Real-time Update Service
Requirements:
- Push leaderboard updates to clients
- Notify players of rank changes
Implementation:
Option 1: WebSockets
- Maintain persistent connections
- Push updates immediately
- Higher server load
Option 2: Server-Sent Events (SSE)
- One-way push from server
- Simpler than WebSockets
- Good for leaderboard updates
Option 3: Polling
- Client polls every few seconds
- Simple but less efficient
Recommended: Hybrid
- WebSockets for active players (top 1000)
- Polling for others
- Use message queue (Kafka) to distribute updates
Flow:
- Score update triggers ranking recalculation
- Publish update event to Kafka
- Real-time service consumes and pushes to clients
- Clients receive updated leaderboard
5. Historical Leaderboard Service
Responsibilities:
- Store leaderboard snapshots
- Serve historical queries
Snapshot Strategy:
- Daily snapshots at midnight UTC
- Weekly snapshots for weekly leaderboards
- Monthly snapshots for long-term storage
Storage:
- Store top 10,000 players per snapshot
- Compress old snapshots
- Archive to cold storage after 1 year
Detailed Design
Data Structure: Redis Sorted Sets
Why Redis Sorted Sets?
- Efficient ranking operations
- O(log N) complexity for inserts/updates
- Built-in range queries
- Atomic operations
- High performance
Key Operations:
Add/Update Score:
ZADD leaderboard:global:1 {score} {user_id}
Get Top N:
ZREVRANGE leaderboard:global:1 0 99 WITHSCORES
Get Rank:
ZREVRANK leaderboard:global:1 {user_id}
ZSCORE leaderboard:global:1 {user_id}
Get Range Around Rank:
ZREVRANGE leaderboard:global:1 {start} {end} WITHSCORES
Remove Player:
ZREM leaderboard:global:1 {user_id}
Leaderboard Types
1. Global Leaderboard
- All players across all games
- Key:
leaderboard:global:{game_id} - Most frequently accessed
2. Friends Leaderboard
- Filtered by player’s friends
- Key:
leaderboard:friends:{user_id}:{game_id} - Requires friend list lookup
3. Weekly Leaderboard
- Resets every week
- Key:
leaderboard:weekly:{week_number}:{game_id} - Archive at end of week
4. Country Leaderboard
- Filtered by country
- Key:
leaderboard:country:{country_code}:{game_id} - Pre-filtered by country
5. Custom Leaderboards
- Time-based (daily, monthly)
- Event-based (tournaments)
- Group-based (clans, teams)
Handling High Write Throughput
Challenge: 100K writes/second
Solutions:
1. Write Batching
- Batch score submissions
- Process in batches of 100-1000
- Reduce Redis operations
2. Write Buffer
- Buffer writes in memory
- Flush periodically
- Handle backpressure
3. Sharding Leaderboards
- Shard by game_id or user_id hash
- Distribute load across Redis instances
- Use consistent hashing
4. Async Processing
- Accept writes immediately
- Process ranking asynchronously
- Eventual consistency acceptable
5. Redis Cluster
- Horizontal scaling
- Shard data across nodes
- High availability
Handling Tie-breaking
Problem: Multiple players with same score
Solution:
- Use composite score:
{score}.{timestamp}.{user_id} - Convert to decimal:
score + (1 / (timestamp + 1)) + (1 / (user_id + 1)) - Ensures deterministic ordering
Example:
Player A: score=1000, timestamp=1234567890, user_id=123
Player B: score=1000, timestamp=1234567891, user_id=456
Composite A: 1000.0000000008103715 (earlier timestamp wins)
Composite B: 1000.0000000008103714
Caching Strategy
Multi-level Caching:
L1: Application Cache (In-memory)
- Top 100 players per leaderboard
- TTL: 100ms
- Very fast access
L2: Redis Cache
- Full leaderboard data
- TTL: 1 second
- Fast updates
L3: Database
- Persistent storage
- Historical data
- Backup for cache
Cache Invalidation:
- Invalidate on score updates
- Use pub/sub for cache invalidation
- Lazy invalidation for non-critical updates
Message Queue Architecture
Use Cases:
- Score Processing: Async score processing
- Ranking Updates: Trigger ranking recalculation
- Real-time Updates: Push updates to clients
- Historical Snapshots: Schedule snapshot creation
Technology: Apache Kafka
Topics:
scores.submitted: New score submissionsleaderboard.updated: Leaderboard update eventsrank.changed: Player rank change eventssnapshot.created: Historical snapshot events
Scalability Considerations
Horizontal Scaling
Stateless Services:
- Score Service, Leaderboard Service
- Scale based on load
- Use load balancer
Stateful Services:
- Redis cluster for caching
- Database sharding
- Message queue partitioning
Redis Scaling
Redis Cluster:
- Shard data across nodes
- Automatic failover
- High availability
Redis Sentinel:
- Master-slave replication
- Automatic failover
- Read scaling
Sharding Strategy:
- Shard by leaderboard type
- Shard by game_id
- Use consistent hashing
Database Scaling
Sharding:
- Shard by user_id
- Shard by game_id
- Cross-shard queries for global leaderboard
Read Replicas:
- Scale reads
- Geographic distribution
- Eventual consistency
Handling Hot Leaderboards
Problem: Popular games have very high traffic
Solutions:
- Dedicated Infrastructure: Separate Redis instances
- Aggressive Caching: Cache top players longer
- Rate Limiting: Limit queries per user
- CDN: Cache static leaderboard pages
Security Considerations
- Score Validation: Prevent cheating
- Server-side validation
- Rate limiting
- Anomaly detection
- Authentication: Verify player identity
- JWT tokens
- API keys
- Rate Limiting: Prevent abuse
- Limit score submissions per user
- Limit leaderboard queries
- Data Privacy: Protect player data
- Encrypt sensitive data
- GDPR compliance
- Anti-cheat: Detect and prevent cheating
- Score validation
- Pattern detection
- Manual review
Monitoring & Observability
Key Metrics:
- Score submission rate
- Leaderboard query latency (p50, p95, p99)
- Cache hit rates
- Redis operations per second
- Error rates
- Rank update latency
Alerts:
- High latency (> 100ms)
- High error rate (> 1%)
- Redis memory usage
- Database connection pool exhaustion
Tools:
- Prometheus + Grafana for metrics
- ELK stack for logging
- Distributed tracing (Jaeger/Zipkin)
Trade-offs and Optimizations
Trade-offs
- Consistency vs Availability
- Choose eventual consistency
- Acceptable delay for rank updates
- Latency vs Accuracy
- Cache for low latency
- Periodic recalculation for accuracy
- Balance both
- Storage vs Compute
- Pre-compute rankings (more storage)
- Compute on-demand (less storage)
- Hybrid approach
Optimizations
- Score Batching
- Batch multiple scores
- Reduce Redis operations
- Improve throughput
- Lazy Ranking
- Update rankings asynchronously
- Accept slight delay
- Better write performance
- Selective Updates
- Only update affected ranks
- Skip updates for players far from top
- Reduce computation
- Compression
- Compress historical data
- Reduce storage costs
- Faster retrieval
What Interviewers Look For
Data Structure Skills
- Sorted Set Usage
- Redis Sorted Sets
- O(log N) operations
- Efficient ranking
- Red Flags: Inefficient data structure, O(N) operations, poor performance
- Ranking Algorithm
- Accurate ranking
- Tie-breaking logic
- Composite scores
- Red Flags: Incorrect ranking, no tie-breaking, simple scores only
- Score Updates
- Atomic updates
- Efficient operations
- Red Flags: Non-atomic, inefficient, race conditions
Real-Time Systems Skills
- Low Latency Reads
- < 50ms query latency
- Multi-level caching
- Red Flags: High latency, no caching, slow queries
- High Write Throughput
- 100K+ writes/second
- Async processing
- Red Flags: Synchronous processing, low throughput, bottlenecks
- Real-Time Updates
- Updates within seconds
- Efficient propagation
- Red Flags: Delayed updates, no real-time, polling
Problem-Solving Approach
- Multiple Leaderboard Types
- Global, friends, weekly
- Efficient filtering
- Red Flags: Single type, inefficient filtering, no variety
- Edge Cases
- Concurrent score updates
- Large player base
- Tie situations
- Red Flags: Ignoring edge cases, no handling
- Trade-off Analysis
- Latency vs accuracy
- Consistency vs performance
- Red Flags: No trade-offs, dogmatic choices
System Design Skills
- Component Design
- Ranking service
- Query service
- Update service
- Red Flags: Monolithic, unclear boundaries
- Sharding Strategy
- Horizontal scaling
- Efficient distribution
- Red Flags: No sharding, vertical scaling, bottlenecks
- Caching Strategy
- Multi-level caching
- Cache invalidation
- Red Flags: No caching, poor strategy, stale data
Communication Skills
- Data Structure Explanation
- Can explain sorted sets
- Understands complexity
- Red Flags: No understanding, vague
- Algorithm Explanation
- Can explain ranking algorithm
- Understands tie-breaking
- Red Flags: No understanding, vague
Meta-Specific Focus
- Data Structures Expertise
- Deep understanding of sorted sets
- Algorithm knowledge
- Key: Show data structures expertise
- Performance Optimization
- Low latency design
- High throughput
- Key: Demonstrate performance focus
Summary
Designing a real-time game leaderboard system requires handling:
- High Write Throughput: 100K+ writes/second
- Low Latency Reads: < 50ms for queries
- Real-time Updates: Updates within seconds
- Multiple Leaderboard Types: Global, friends, weekly, etc.
- Ranking Accuracy: Accurate and consistent rankings
Key Architectural Decisions:
- Redis Sorted Sets: Efficient ranking data structure
- Async Processing: Handle high write throughput
- Multi-level Caching: Low latency reads
- Message Queue: Decouple components
- Sharding: Scale horizontally
- Composite Scores: Handle tie-breaking
Data Structure Choice:
- Redis Sorted Sets: O(log N) operations, built-in ranking
- Perfect for leaderboard use case
- High performance and scalability
Leaderboard Types:
- Global: All players
- Friends: Filtered by friend list
- Weekly: Time-based with reset
- Country: Geographic filtering
- Custom: Event-based, group-based
This design can handle the scale of major gaming platforms while maintaining low latency and high availability for real-time leaderboard updates.