Bird
Raised Fist0
HLDsystem_design~25 mins

One-to-one messaging in HLD - System Design Exercise

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Design: One-to-one Messaging System
Design covers backend architecture, data storage, and message delivery mechanisms. Client UI and encryption details are out of scope.
Functional Requirements
FR1: Allow users to send and receive messages privately between two users
FR2: Support message delivery in real-time with low latency
FR3: Store message history for users to view past conversations
FR4: Support message read receipts to show if a message was read
FR5: Allow users to be online or offline; deliver messages accordingly
FR6: Support up to 1 million active users with up to 10,000 concurrent connections
FR7: Ensure message order is preserved between two users
Non-Functional Requirements
NFR1: System should have p99 latency under 200ms for message delivery
NFR2: Availability target of 99.9% uptime (about 8.77 hours downtime per year)
NFR3: Messages must be durable and not lost
NFR4: Support mobile and web clients
NFR5: Privacy: messages are only visible to the two users involved
Think Before You Design
Questions to Ask
❓ Question 1
❓ Question 2
❓ Question 3
❓ Question 4
❓ Question 5
❓ Question 6
Key Components
API Gateway or Load Balancer
Authentication Service
Messaging Service (handles sending and receiving)
Message Queue or Pub/Sub system for real-time delivery
Persistent Storage (database) for message history
Cache layer for recent messages or user presence
Notification Service for offline users
Design Patterns
Publish-Subscribe pattern for message delivery
Event-driven architecture for message processing
CQRS (Command Query Responsibility Segregation) for separating reads and writes
Sharding and partitioning for database scalability
WebSocket or long polling for real-time communication
Reference Architecture
Client (Web/Mobile)
    |
    v
API Gateway / Load Balancer
    |
Authentication Service
    |
Messaging Service <--> Cache (User presence, recent messages)
    |
Message Queue / Pub-Sub
    |
Persistent Storage (Database)
    |
Notification Service (for offline users)
Components
API Gateway / Load Balancer
Nginx, AWS ALB
Route client requests to backend services and balance load
Authentication Service
OAuth 2.0, JWT
Verify user identity and issue tokens
Messaging Service
Node.js or Go microservice
Handle sending, receiving, and ordering of messages
Message Queue / Pub-Sub
Apache Kafka or Redis Streams
Enable real-time message delivery and decouple sender and receiver
Persistent Storage
PostgreSQL or Cassandra
Store message history and user metadata
Cache
Redis
Store user presence status and recent messages for fast access
Notification Service
Firebase Cloud Messaging or APNs
Send push notifications to offline users
Request Flow
1. 1. User client connects to API Gateway and authenticates via Authentication Service.
2. 2. Client opens a WebSocket connection to Messaging Service for real-time communication.
3. 3. When User A sends a message to User B, Messaging Service receives the message.
4. 4. Messaging Service writes the message to Persistent Storage to ensure durability.
5. 5. Messaging Service publishes the message to Message Queue / Pub-Sub.
6. 6. Messaging Service subscribes to the queue and delivers the message to User B if online via WebSocket.
7. 7. If User B is offline, Notification Service sends a push notification.
8. 8. User B receives the message and sends a read receipt back through Messaging Service.
9. 9. Messaging Service updates message status and notifies User A.
10. 10. Cache stores user presence and recent messages to optimize delivery and UI updates.
Database Schema
Entities: - User: user_id (PK), username, status - Message: message_id (PK), sender_id (FK User), receiver_id (FK User), content, timestamp, status (sent, delivered, read) - Conversation: conversation_id (PK), user1_id (FK User), user2_id (FK User) Relationships: - One Conversation between two Users (1:1) - Messages belong to one Conversation (1:N) - Message sender and receiver reference User entity
Scaling Discussion
Bottlenecks
Messaging Service CPU and memory limits with high concurrent connections
Database write throughput for storing messages
Message Queue throughput and latency under heavy load
Cache size and eviction policies for user presence and recent messages
Notification Service limits for push notifications
Solutions
Scale Messaging Service horizontally with stateless design and sticky sessions or distributed session management
Partition database by user or conversation ID (sharding) to distribute load
Use a high-throughput distributed message queue like Kafka with multiple partitions
Implement cache sharding and optimize eviction policies; use TTL for presence data
Batch notifications and use multiple notification providers to distribute load
Interview Tips
Time: Spend 10 minutes clarifying requirements and constraints, 15 minutes designing architecture and data flow, 10 minutes discussing scaling and trade-offs, 10 minutes for questions and wrap-up.
Emphasize real-time delivery with WebSocket and message queue
Discuss durability and ordering guarantees with persistent storage
Explain how offline users are handled with notifications
Highlight scalability strategies like sharding and horizontal scaling
Mention security and privacy considerations for one-to-one messaging

Practice

(1/5)
1. What is the primary role of the server in a one-to-one messaging system?
easy
A. To allow users to send messages directly without any intermediary
B. To store all messages permanently without delivering them
C. To receive messages from the sender and deliver them to the receiver
D. To broadcast messages to all users in the system

Solution

  1. Step 1: Understand message flow in one-to-one messaging

    Messages are sent from one user to another through a server acting as an intermediary.
  2. Step 2: Identify server's role

    The server receives messages from the sender and forwards them to the intended receiver, ensuring delivery and possibly storing temporarily.
  3. Final Answer:

    To receive messages from the sender and deliver them to the receiver -> Option C
  4. Quick Check:

    Server acts as message relay = B [OK]
Hint: Server relays messages between users, not direct connection [OK]
Common Mistakes:
  • Thinking users connect directly without server
  • Assuming server only stores without forwarding
  • Confusing one-to-one with broadcast messaging
2. Which component is essential to ensure message privacy in a one-to-one messaging system?
easy
A. End-to-end encryption
B. Message queue
C. Load balancer
D. Caching layer

Solution

  1. Step 1: Identify privacy needs in messaging

    Privacy means only sender and receiver can read the message content.
  2. Step 2: Match privacy solution

    End-to-end encryption encrypts messages so only sender and receiver can decrypt them, ensuring privacy.
  3. Final Answer:

    End-to-end encryption -> Option A
  4. Quick Check:

    Privacy needs encryption = C [OK]
Hint: Privacy means encrypt messages end-to-end [OK]
Common Mistakes:
  • Confusing load balancer as privacy tool
  • Thinking caching secures messages
  • Assuming message queue provides privacy
3. Consider this simplified message flow code snippet for one-to-one messaging:
def send_message(sender, receiver, message):
    server.store_message(sender, receiver, message)
    server.deliver_message(receiver)

send_message('Alice', 'Bob', 'Hello')
What is the expected output or result of this code?
medium
A. Syntax error due to missing parameters
B. Message is delivered to Alice instead of Bob
C. Message is stored but never delivered
D. Message 'Hello' is stored and delivered to Bob

Solution

  1. Step 1: Analyze function calls

    The function stores the message from Alice to Bob, then delivers it to Bob.
  2. Step 2: Check message flow correctness

    Message is stored correctly and delivery is triggered for Bob, the intended receiver.
  3. Final Answer:

    Message 'Hello' is stored and delivered to Bob -> Option D
  4. Quick Check:

    Store then deliver to receiver = D [OK]
Hint: Store then deliver to receiver means message sent correctly [OK]
Common Mistakes:
  • Confusing sender and receiver in delivery
  • Assuming message is not delivered after storing
  • Thinking code has syntax errors
4. In a one-to-one messaging system, this code snippet causes messages to never reach the receiver:
def deliver_message(receiver, message):
    if receiver.is_online == False:
        return
    send_to_client(receiver, message)
What is the main issue causing message delivery failure?
medium
A. The function sends messages to the wrong user
B. Messages are dropped if receiver is offline without queuing
C. There is a syntax error in the if condition
D. The message variable is undefined

Solution

  1. Step 1: Understand delivery condition

    The function returns early if the receiver is offline, skipping delivery.
  2. Step 2: Identify missing handling

    Messages are not queued or stored for later delivery, so offline users never get messages.
  3. Final Answer:

    Messages are dropped if receiver is offline without queuing -> Option B
  4. Quick Check:

    Offline receiver drops messages = A [OK]
Hint: Offline users need message queue to avoid drops [OK]
Common Mistakes:
  • Thinking syntax error causes failure
  • Assuming wrong user receives message
  • Assuming offline messages are automatically queued
5. You are designing a scalable one-to-one messaging system for millions of users. Which approach best ensures message delivery even if the receiver is offline?
hard
A. Use a message queue to store undelivered messages and retry delivery when receiver is online
B. Drop messages if receiver is offline to save storage and bandwidth
C. Broadcast messages to all users and let receiver filter them
D. Send messages only when both users are online simultaneously

Solution

  1. Step 1: Understand offline delivery challenge

    Receivers may be offline, so messages must be stored to avoid loss.
  2. Step 2: Choose scalable solution

    Message queues store undelivered messages and retry delivery when receiver reconnects, ensuring reliability and scalability.
  3. Final Answer:

    Use a message queue to store undelivered messages and retry delivery when receiver is online -> Option A
  4. Quick Check:

    Queue undelivered messages for offline users = A [OK]
Hint: Queue messages for offline users to ensure delivery [OK]
Common Mistakes:
  • Dropping messages loses data
  • Broadcast wastes resources and breaks privacy
  • Requiring both online limits usability