System Design: Chat Application

Designing a chat app isn’t about building features in the dark. It’s a journey of understanding, refining, and then crafting an experience that truly serves its users. In this blog post, we’ll dissect the critical steps before diving into the intricate mechanics of a chat app system design.

Unveiling the Needs: A Conversation, Not a Monologue

Our first stop is clarity. Imagine building a bustling marketplace when the user envisions a cozy coffee shop. Misaligned expectations lead to disappointing outcomes. So, we ask those insightful questions that illuminate the true vision:

One-on-one or group chat? This sets the foundation, defining core functionalities and scaling needs.

Mobile, web, or both? Platform choice impacts everything from interface design to technical architecture.

Start-up or massive scale? Understanding the user base informs decisions on server infrastructure and growth strategies.

These questions are just the beginning. Each answer unlocks further details, like group size limits, desired features, and data storage requirements. It's a conversation, not a monologue, where collaboration between designer and interviewer paves the way for a truly meaningful system.

This chapter focuses on a familiar chat app. Here's what defines its essence:

Fast and fluid one-on-one chat: Every message reaches its destination in a blink, fostering seamless conversation.

Compact group gatherings: Up to 100 members can connect and collaborate, striking a balance between intimacy and inclusivity.

Always in the know: Online indicators keep you connected to your circle, ensuring you never miss a beat.

Multi-device magic: One account, multiple devices, seamless flow. Be present wherever you are, whoever you're with.

The power of push: Timely notifications bridge the gap between online and offline, keeping you in the loop even when the app is closed.

Bridging the Gap: Choosing the Right Protocol for Your Chat App

In the intricate world of designing a chat app, communication protocols take center stage. They’re the invisible highways carrying messages from sender to receiver, ensuring seamless conversation flows. But with a plethora of options, choosing the right protocol can be baffling. Let’s explore the key players and their strengths on both the sending and receiving ends of your chat app masterpiece.

The Sender’s Side: Reliable Delivery with HTTP

When it comes to sending messages, simplicity reigns supreme. HTTP, the ubiquitous web protocol, takes the cake. Clients initiate requests, sending messages to the chat service. With “keep-alive” connections, persistent communication becomes a breeze, minimizing resource overhead. No wonder giants like Facebook initially relied on HTTP for message delivery. It’s efficient, familiar, and gets the job done.

The Receiver’s Side: Where Things Get Interesting

Receiving messages, however, throws a curveball. HTTP’s client-initiated nature poses a challenge – how can the server proactively push messages to waiting clients? Fear not, for ingenious techniques have emerged:

Polling: It’s the simplest, though inefficient. Clients constantly ask the server “Any new messages?”. While straightforward, it bombards the server with needless requests, draining resources.

Long Polling: A smarter take on polling. Clients hold open a long-lived connection, waiting for the server to push updates. This reduces unnecessary requests, but still keeps the connection tied up.

WebSockets: The real hero of real-time communication. WebSockets establish persistent, bi-directional connections, allowing both client and server to send and receive messages instantly. No more polling, no more waiting on closed connections. WebSockets truly unlock the dynamic, responsive experience we expect from modern chat apps.

So, Which Protocol Wears the Crown?
For the sender, HTTP remains a solid choice. It’s reliable, familiar, and scales well. But for the receiver, WebSockets hold the key to smooth, instantaneous messaging. Their bi-directional nature and efficient communication make them the preferred protocol for building truly engaging chat experiences.

Here’s how WebSocket empowers real-time communication:

Initiation and Upgrade:
A WebSocket connection begins its life as a standard HTTP request from the client. 
Through a well-defined handshake, this connection undergoes an upgrade, transforming into a persistent, bi-directional communication channel.

Persistent and Bi-Directional:
This persistent connection allows both client and server to send and receive messages without the need for constant polling or request-response cycles.
It’s like an open phone line between the two, ensuring a fluid exchange of information in real time.

Firewall-Friendly:
WebSockets leverage the common HTTP ports 80 and 443, making them compatible with most firewalls.
This means uninterrupted communication even in environments with strict security measures.

Unifying Sending and Receiving:
While HTTP is a viable option for sending messages, WebSockets’ bi-directional nature makes it equally suitable for both sending and receiving.
This simplifies the overall design and streamlines implementation on both client and server sides.

Efficient Connection Management:
Persistent connections require careful management on the server-side to ensure optimal resource utilization and scalability.
Techniques such as load balancing, connection pooling, and efficient message handling are crucial for maintaining a smooth chat experience for a large user base.

WebSockets have become the cornerstone of real-time communication in modern chat applications. Their ability to establish persistent, bi-directional connections enables instant messaging, live updates, and a truly interactive user experience. By embracing WebSockets and mastering efficient connection management, you can create chat apps that foster effortless, real-time conversations that captivate users.

Remember, every chat app is unique, and the optimal protocol choice depends on your specific needs and desired user experience. Consider factors like scalability, latency, and desired features before making your call.

Stateless Services:

Meaning: These services don’t store any client-specific data across requests. They treat each request independently, without relying on information from previous interactions.

Chat Application Stateless Services:

  • Authentication Service: User registration and login
  • User Profile Service: Retrieving user profiles
  • Service Discovery: Recommend best available chat server
  • Group Management Service: Handling group chat memberships

Benefits:

  • Scalability: Easily add more servers to handle increased load.
  • High availability: Individual servers can fail without disrupting the entire system.
  • Simpler deployment and maintenance: No need to manage complex session states.

Stateful Services:

Meaning: These services maintain client-specific data across multiple requests, creating a “session” to track user progress.

Chat Application Stateful Services:

  • Real-time message delivery using WebSockets
  • Online presence indicators
  • Tracking unread messages
  • Persistent chat history
  • Group chat synchronization

Benefits:
Enhanced user experience: Enables features that require real-time updates and persistent data storage.

Drawbacks:
Potential scalability challenges: Requires careful load balancing and session management.
Fault tolerance considerations: Server failures can lead to session loss and data inconsistencies.

 

Third Party Integration (Psuh Notifications)

 

No chat experience is truly complete without push notifications. They act as digital heralds, piercing through closed apps to whisper “Hey, you’ve got a message!” This seemingly simple feature plays a pivotal role in keeping users engaged and connected.

Integrating push notifications seamlessly is an art form. It’s about striking the perfect balance between informing users without bombarding them. Sending irrelevant or untimely notifications can quickly turn a helpful nudge into a pesky annoyance.
But when done right, push notifications become an extension of the app itself. They act as a bridge, drawing users back into the vibrant world of conversations even when they’re busy exploring other digital realms.

 

Data Models

At the heart of every captivating chat experience lies a carefully crafted data layer, ready to store and deliver conversations seamlessly. But choosing the right database for the job isn’t always straightforward. Let’s dive into the data storage considerations that empower effective chat app design.

Delving Deeper into Data Types and Patterns:
Generic Data: User profiles, settings, and friend lists find a comfortable home in robust relational databases. Replication and sharding techniques ensure high availability and scalability, even as your user base grows.
Chat History: The heart of conversation, chat history demands a unique approach. Consider these key characteristics:
Volume: Chat apps handle a staggering amount of data, reaching billions of messages daily.
Access Patterns: Recent chats are accessed most frequently, while older conversations are typically left undisturbed.
Random Access: Features like search, mentions, and message jumping necessitate efficient random data access.
Read-Write Ratio: Typically, chat apps maintain a balanced 1:1 read-to-write ratio for one-on-one conversations.
 
Why do key-value stores emerge as the favored choice for chat history storage?
Horizontal Scaling: They effortlessly expand to accommodate growing data volumes, ensuring seamless performance.
Low Latency Access: They deliver lightning-fast data retrieval, even for large datasets, keeping conversations flowing smoothly.
Long Tail Handling: Unlike relational databases, key-value stores efficiently manage chat history’s long tail, where recent chats are accessed far more often than older ones.
Proven Reliability: Industry giants like Facebook Messenger (using HBase) and Discord (using Cassandra) have successfully harnessed key-value stores to power their chat experiences, demonstrating their real-world effectiveness.

Mapping the Message Landscape:


1-on-1 Chats:
  • Schema: message_id, message_from, message_to, content and created_at
  • Primary Key: message_id (guarantees message sequence)
  • Reason for message_id to be primary key: created_at timestamps can’t reliably determine order if multiple messages are sent simultaneously.

Group Chats:
  • Schema: channel_id, message_id, user_id, content, created_at
  • Composite Primary Key: (channel_id, message_id)
Explanation:
  • channel_id partitions data for efficient queries within specific group conversations.
  • message_id maintains message order within each channel.
The Enigma of Message IDs:
Purpose: Ensuring accurate message ordering, crucial for logical conversation flow.

Requirements:
  • Uniqueness: Each message must possess a distinct identifier.
  • Sortability: Message IDs should reflect temporal order, with newer messages having higher IDs.
Generating Message IDs in NoSQL Worlds:
Auto-Increment Alternatives:
While traditional relational databases often offer auto-increment features for primary keys, NoSQL databases typically require different approaches. Here are two common strategies:
Global Sequence Number Generators:
Snowflake ID generator
  • Pros: Guarantees global uniqueness across all channels and conversations.
  • Cons: Potential complexity in distributed systems.

Local Sequence Number Generators:
  • Uniqueness scope: Within individual channels or group conversations.
  • Pros: Simpler implementation, often sufficient for maintaining message order within specific contexts.
  • Cons: Might require additional logic if global message ordering is ever needed.

Leave a Comment

Your email address will not be published. Required fields are marked *