As a user I should be able to broadcast my presence status (online, idle, offline) to my friends in real time.
As a user I should be able to receive updates about presence status changes for friends in real time.
Users should be able to friend other users.
Non-Functional:
Latency:
The service should propagate presence status changes within approximately 1 second to ensure real-time responsiveness for users. Notifications for offline or idle status changes should ideally be triggered after 15 seconds of inactivity or connection loss.
Scalability:
The system must support up to 1 billion users, with 500 million monthly active users and 100 million users online concurrently. This entails handling 5–10 million heartbeat messages per second and propagating hundreds of thousands of presence changes per second.
Availability:
High availability is critical, with no single point of failure. The system needs to remain operational with minimal downtime, ensuring users' presence information is consistently updated.
Throughput:
Must handle large volumes of events (status changes, heartbeats) efficiently, minimizing delays and ensuring prompt delivery across potentially vast server infrastructure.
Security:
Protect status updates from unauthorized access or spoofing, ensuring only authorized users see presence changes. Secure authentication and encryption protocols are required for all communications.
Data Durability:
While the real-time data for presence (online, idle, offline) can be ephemeral, historical logs (for analytics) must have durable storage, supporting long-term analysis without impacting real-time performance.
Performance:
The system should ensure low-latency updates despite high load, with well-optimized infrastructure to accommodate growth and fluctuating peak usage efficiently.
Capacity estimation
Concurrent connections - the system needs to support 100 million users online concurrently, 5–10 million heartbeat messages per second, and hundreds of thousands of presence changes per second being distributed to an average of 100 friends per user.
Storage - We will keep a key/value store for fast lookup of current user presence status as well as long term storage for future analytics with historical presence data. Since we have hundreds of thousands of presence changes per second (estimated 500,000). This means we could end up storing:
500,000 * 86400 = 43,200,000,000 or ~43.2 billion presence status changes per day
43.2 billion * 365 = 15.8 trillion presence status changes per year
API design
sendHeartBeat(user)
sendActivity(user)
connect(user)
disconnect(user)
createFriendship(fromUser, toUser)
getFriendships(user)
Database design
Friendships - graph database to represent friendships between users where a user is a vertex and an edge between users indicates a friendship between the users.
Heartbeats - Key value database mapping userIds to timestamp of their last heartbeat received.
Activity - Key value database mapping userIds to timestamp of their last activity received.
Live presence status - Key value database storing live presence status of a user. Stores userId as the primary key, status and last_updated_time.
Historical presence data warehouse - Data warehouse to keep historical data surrounding presence changes. Changes are appended rather than being overridden like the live presence status table.
High-level design
Heartbeat service - responsible for receiving and storing heartbeats and sending an "offline" status event if no heartbeats have been detected after 15 seconds.
Activity service - responsible for receiving and storing activites and sending an "offline" status event if no heartbeats have been detected after 15 seconds.
Presence service - websocket service that sends presence change events to connected friends for a given user associated with the presence change.
Friendship service - responsible for storage and CRUD on friend relationships between users
Authentication service - Responsible for creating and decrypting auth tokens for users.
Request flows
User comes online with active activity - When a user comes online, they connect to an instance of presence service, start sending heartbeats to heartbeat service, and start sending client side events to activity service. Their online status is relayed to all other instances of presence services via our pub/sub presence status queue and those instances relay the user's status to all of their friends that are connected to that instance.
User becomes idle - The user is still sending heartbeats within the valid time frame (15 secs) and not disconnected. However, they haven't been active for 15 seconds as the activity service has not received any client side events for 15 seconds. Because of this, the activity service sends an "idle" status for the user to our pub/sub presence status queue. Then all presence service instances pick up this event and relay it to all friends of the user that are connected to that particular instance.
User becomes offline - this occurs either when a user disconnects from their presence service instance or when a heartbeat has not been received for 15 seconds. In the event of disconnect the presence service instance the user was connected to will send a "offline" event to the pub/sub presence status queue and all presence service instances will pick this up and relay it back to connected friends of that user. In the event that a heartbeat has not been received for 15 seconds then the heartbeat service will send a "offline" event to the pub/sub presence status queue and all presence service instances will pick this up and relay it back to connected friends of that user.
Detailed component design
Presence service -
Activity service -
Trade offs/Tech choices
Explain any trade offs you have made and why you made certain tech choices...
Failure scenarios/bottlenecks
Try to discuss as many failure scenarios/bottlenecks as possible.
Future improvements
Instead of storing presence statuses and friendships in separate tables we can store the friendships and user presence status in the same table, this eliminates the need to have a separate friendship service and reduces the latency as presence service does not need to make a separate network call to the friendship service.