Our chat service architecture is designed to support high-volume, real-time messaging while ensuring message integrity and user privacy. By integrating advanced technologies and algorithms, we manage to maintain high performance and reliability.
-
Sticky Sessions: Each user's connection is managed via a sticky session, where a hash function determines which server node will handle the user's messages. This ensures consistent performance and minimizes latency.
-
Message Filtering and Security: Upon receiving a message, the chat server performs a quick scan for any abusive language using a Trie data structure, which processes content in O(length of message) time. This ensures all communications are safe and professional.
-
Real-Time Broadcasting with Redis PUB/SUB: After processing, messages are immediately published to a Redis PUB/SUB system, ensuring that all participants in a conversation receive messages without delay.
-
Unique Identification with Snowflake Algorithm: Every message is tagged with a unique ID generated by the Snowflake algorithm, facilitating easy tracking and management of messages across the system.
-
Kafka and Sharded Databases: Kafka consumers batch and handle incoming messages to optimize flow control and load balancing. These messages are then stored in sharded databases, which are accessed through a connection pool to maximize efficiency and scalability.
Our chat service architecture incorporates several optimizations to enhance throughput and system efficiency. These improvements are strategically implemented to ensure rapid message delivery and robust scalability.
-
Channel-Based Hashing for Sticky Sessions: By hashing based on channel ID for sticky sessions, we ensure that users within the same chat room or channel are handled by the same server node. This approach reduces the load on the Redis PUB/SUB system and accelerates message delivery, reinforcing our real-time communication features.
-
Snowflake Algorithm for Message IDs: Utilizing the Snowflake algorithm allows each message to be uniquely identified and retrieved directly by its ID. This method organizes records in the database according to the time they are sorted, significantly enhancing the speed of historical message retrieval.
-
Connection Pooling and Batch Inserts: To optimize data transfer and database interaction, we employ connection pooling for our sharded databases. This strategy speeds up the process of pushing data and reduces network I/O. Additionally, batching and bulk inserts are used to decrease the load on our PostgreSQL databases, further improving performance.
-
Database Sharding Based on Channel ID: Our databases are sharded based on the channel ID, which simplifies scaling as each database shard stores only messages pertinent to specific channels. This segmentation effectively manages data volume and enhances query performance by localizing data access.
These optimizations are crucial for maintaining high performance and reliability as our chat service scales up to accommodate more users and channels.
https://documenter.getpostman.com/view/28829311/2sAYQXoYKJ
Screencast.from.14-01-25.09.54.02.PM.IST.webm
Our chat application enhances security and efficiency by utilizing presigned URLs for file uploads. This method allows users to securely upload files directly to our cloud storage without routing them through our chat server, thereby reducing latency and server load.
When a user selects a file for upload, the chat server generates a presigned URL that grants temporary access to the storage bucket. The file is then uploaded directly to the storage bucket(S3) using this URL, ensuring that the data transfer is secure and direct.
Content Delivery Network (CDN) Integration: To implement a CDN to further enhance the delivery speeds of static files like images and videos across global locations. This will ensure users experience faster loading times and improved performance as shown in design.
The Heartbeat Service in our chat application plays a crucial role in managing connection states. This service ensures that the application can handle user presence and disconnections gracefully.
-
Ping/Pong Mechanism: The client (frontend) sends a 'ping' message at regular intervals to the chat server via a WebSocket connection. In response, the server sends back a 'pong' message, confirming the connection's activeness.
-
Publish to Pub/Sub: Upon receiving a ping, the chat server publishes a heartbeat message to a dedicated Pub/Sub channel named "HEARTBEAT".
-
Subscriber Actions: Services subscribed to the HEARTBEAT channel listen for these messages and update the Time-To-Live (TTL) of each user's session in Redis. Maintaining a connection pool with redis.
-
Connection Monitoring: The chat server is also subscribed to a Redis channel that notifies about TTL expirations (
__keyevent@0__:expired
). If a user's TTL expires (indicating inactivity), the chat server receives this expiration event and terminates the inactive connection, ensuring system resources are efficiently managed.
To run the chat app backend on your machine:
-
Clone the repository:
git clone https://github.com/SubhamMurarka/chat_app.git
-
Configure sample.env file.
-
Run with Docker
docker-compose up -d --build