| Scale | Users | Active Connections | Data Stored | Traffic Characteristics | System Changes |
|---|---|---|---|---|---|
| Small | 100 | ~100 concurrent | MBs (presence states) | Low, few updates per second | Single server, simple DB, no caching |
| Medium | 10,000 | ~5,000 concurrent | GBs (presence logs, user states) | Moderate, frequent presence updates | Load balancer, DB replicas, caching layer |
| Large | 1,000,000 | ~500,000 concurrent | TBs (history, analytics) | High, real-time updates, many events/sec | Horizontal scaling, sharding, pub/sub messaging |
| Very Large | 100,000,000 | ~50,000,000 concurrent | Petabytes (long-term storage) | Very high, global distribution, multi-region | Global CDN, geo-sharding, multi-region DB, edge caching |
Online presence system in HLD - Scalability & System Analysis
Start learning this pattern below
Jump into concepts and practice - no test required
At small scale, the database is the first bottleneck because it must handle many frequent presence updates and queries. As users grow, the DB write throughput and connection limits are stressed first.
- Database scaling: Use read replicas to offload reads, connection pooling, and write sharding to distribute load.
- Caching: Cache presence states in fast in-memory stores like Redis to reduce DB hits.
- Horizontal scaling: Add more application servers behind load balancers to handle concurrent connections.
- Messaging: Use pub/sub systems (e.g., Kafka, Redis Streams) to propagate presence updates efficiently.
- Global distribution: Geo-shard data and use CDNs or edge caches to reduce latency for worldwide users.
- Requests per second: For 1M users with 50% active, ~500K concurrent connections, each sending updates every 10 seconds -> ~50K QPS.
- Storage: Presence states are small (~100 bytes per user), but history logs grow fast. For 1M users, daily logs ~10GB; yearly ~3.6TB.
- Bandwidth: Each update ~100 bytes, 50K QPS -> ~5MB/s (~40Mbps), manageable with 1Gbps network.
Start by defining the scale and key metrics (users, connections, update frequency). Identify the first bottleneck (usually DB). Then discuss scaling strategies step-by-step: caching, read replicas, horizontal scaling, messaging, and global distribution. Always justify why each solution fits the bottleneck.
Your database handles 1000 QPS. Traffic grows 10x to 10,000 QPS. What do you do first?
Answer: Add read replicas and implement caching to reduce direct DB load before considering sharding or adding more servers.
Practice
Solution
Step 1: Understand the role of presence system
An online presence system tracks user activity to know if they are online or offline.Step 2: Differentiate from other chat features
Message storage, encryption, and password management are separate features not handled by presence systems.Final Answer:
To track if users are currently online or offline -> Option AQuick Check:
Presence system = user online status [OK]
- Confusing presence with message storage
- Thinking presence handles security features
- Mixing presence with account management
Solution
Step 1: Identify presence tracking events
Presence systems useconnect,heartbeat, anddisconnectto track user activity.Step 2: Recognize unrelated events
message_sendrelates to sending chat messages, not presence tracking.Final Answer:
message_send-> Option AQuick Check:
Presence events exclude message sending [OK]
- Assuming message events track presence
- Confusing heartbeat with message_send
- Ignoring disconnect event importance
user_last_seen = 0
current_time = 10
heartbeat_interval = 5
if current_time - user_last_seen <= heartbeat_interval:
status = 'online'
else:
status = 'offline'Solution
Step 1: Calculate time difference
current_time - user_last_seen = 10 - 0 = 10 seconds.Step 2: Compare with heartbeat interval
10 <= 5 is false, so status is set to 'offline'.Final Answer:
"offline" -> Option CQuick Check:
Time diff > heartbeat means offline [OK]
- Mixing up less than and greater than
- Forgetting to subtract last seen time
- Assuming status is always online
def update_status(last_seen, current_time, heartbeat=10):
if current_time - last_seen > heartbeat:
return 'online'
else:
return 'offline'Solution
Step 1: Analyze the condition meaning
If time difference is greater than heartbeat, user should be offline, not online.Step 2: Correct the comparison
The condition should return 'offline' when difference > heartbeat, so the comparison sign must be reversed.Final Answer:
The comparison sign should be reversed -> Option BQuick Check:
Time diff > heartbeat means offline [OK]
- Returning online when user is inactive
- Misunderstanding heartbeat meaning
- Ignoring return type correctness
Solution
Step 1: Evaluate centralized database approach
Querying a centralized DB for every request causes high latency and bottlenecks at scale.Step 2: Consider distributed cache with TTL and heartbeats
This approach keeps presence data fresh, reduces DB load, and supports real-time updates efficiently.Step 3: Analyze other options
Ignoring heartbeats or updating once per day leads to stale presence info, unsuitable for real-time apps.Final Answer:
Use distributed in-memory cache with TTL and heartbeat updates from clients -> Option DQuick Check:
Distributed cache + heartbeat = scalable real-time presence [OK]
- Relying on centralized DB for real-time presence
- Ignoring heartbeat updates causing stale data
- Updating presence too infrequently
