Chat App (WhatsApp) ডিজাইন
- ●WhatsApp-এর মূল হলো persistent WebSocket connection, যেটা দিয়ে real-time message push করা যায়।
- ●Message-এর তিন অবস্থা — sent, delivered, read — এবং online presence ট্র্যাক করা মূল চ্যালেঞ্জ।
- ●User offline থাকলে message queue-তে জমে থাকে আর push notification পাঠানো হয়, group chat-এ fan-out লাগে।
WhatsApp প্রতিদিন কোটি কোটি message handle করে — অথচ message প্রায় instant পৌঁছে যায়, আর সবুজ দুটো টিক দেখলেই বুঝি অন্যজন পড়ে ফেলেছে। এই simplicity-র পেছনে আছে চমৎকার একটা system design। চলো একজন senior engineer যেভাবে interview-তে ব্যাখ্যা করবে, সেভাবে ধাপে ধাপে দেখি।
১. সমস্যা বোঝা (Requirements)
প্রথমেই ঠিক করতে হবে আমরা ঠিক কী বানাচ্ছি। সব feature একসাথে নয় — মূল জিনিসগুলো ধরি।
Functional Requirements (কী কাজ করবে):
- দুজন user-এর মধ্যে one-to-one message পাঠানো ও receive করা।
- Message delivery status — sent, delivered, read (একটা টিক, দুটো টিক, নীল টিক)।
- User online/offline presence দেখানো ("last seen" সহ)।
- Group chat — একসাথে অনেকজনের সাথে কথা।
- User offline থাকলে message জমা থাকবে, online হলে deliver হবে।
- Offline user-কে push notification।
Non-functional Requirements (কেমনভাবে কাজ করবে):
- Low latency — message যেন এক সেকেন্ডের মধ্যে পৌঁছায়।
- High availability — সার্ভিস সবসময় চালু থাকবে।
- Consistency — message order ঠিক থাকবে, কোনো message হারাবে না।
- Scalability — কোটি কোটি concurrent user সামলানো।
পুরোনো দিনের ডাকপিয়নের কথা ভাবো। তুমি চিঠি দিলে — সেটা "পাঠানো" হলো। ডাকপিয়ন বাড়িতে পৌঁছে দিল — "delivered"। প্রাপক চিঠি খুলে পড়ল — "read"। WhatsApp শুধু এই পুরো জিনিসটা মিলিসেকেন্ডে করে।
২. স্কেল আন্দাজ (Estimation)
হিসাব করলে বোঝা যায় system কত বড় হবে। আনুমানিক napkin math:
ধরি:
DAU (Daily Active Users) = 50 কোটি = 500M
প্রতি user দিনে message = 40 টি
মোট message/দিন = 500M × 40 = 20 বিলিয়ন/দিন
QPS (Queries Per Second):
লেখা (write) QPS গড় = 20B / 86400 ≈ 230,000 msg/sec
পিক সময় (×3) ≈ 700,000 msg/sec
Storage (ধরি প্রতি message ~300 bytes মেটাডাটাসহ):
প্রতিদিন = 20B × 300B = 6 TB/দিন
প্রতি বছর = 6 TB × 365 ≈ 2.2 PB/বছর
Concurrent connections:
পিক সময়ে online users ≈ 50M – 100M
প্রতি server ~65k connection → লাগবে ~1500+ connection server
মূল শিক্ষা: এখানে message storage বিশাল, আর সবচেয়ে বড় challenge হলো লক্ষ লক্ষ persistent connection একসাথে ধরে রাখা।
৩. API ডিজাইন
Real-time অংশটা WebSocket দিয়ে, আর বাকিগুলো সাধারণ REST দিয়ে।
// WebSocket দিয়ে real-time message (persistent connection)
WS /connect?token=<jwt> // connection খোলা
// WebSocket-এর ভেতর message events:
{ "type": "send_message", "to": "userB", "text": "...", "tempId": "..." }
{ "type": "message_ack", "messageId": "...", "status": "delivered" }
{ "type": "read_receipt", "messageId": "..." }
{ "type": "presence", "userId": "userB", "status": "online" }
// REST (এক-বারের কাজের জন্য)
POST /v1/messages // fallback message পাঠানো
GET /v1/messages?chatId=&since= // history/sync নেওয়া
POST /v1/groups // group তৈরি
GET /v1/users/{id}/presence // last seen
৪. ডেটা মডেল
প্রধান entity গুলো:
| Table/Collection | মূল field |
|---|---|
| users | user_id, name, phone, last_seen, public_key |
| messages | message_id, chat_id, sender_id, content, created_at, status |
| chats | chat_id, type (single/group), member_ids |
| group_members | group_id, user_id, role, joined_at |
| inbox / message_queue | user_id, message_id (offline delivery-র জন্য) |
SQL vs NoSQL choice: Message লেখার volume বিশাল (সেকেন্ডে লক্ষ লক্ষ write) এবং query pattern simple — "এই chat-এর message timeline দাও"। তাই messages-এর জন্য NoSQL (Cassandra/HBase) আদর্শ, যেখানে chat_id partition key আর created_at sort key হিসেবে রাখলে timeline read খুব দ্রুত হয় এবং horizontal scaling সহজ। অন্যদিকে user profile, group membership-এর মতো structured ও কম-পরিবর্তনশীল data-র জন্য SQL (PostgreSQL) ভালো।
৫. হাই-লেভেল ডিজাইন
মূল components:
- Client (App): WebSocket connection ধরে রাখে।
- Load Balancer: connection ছড়িয়ে দেয় servers-এ।
- WebSocket / Chat Servers: persistent connection হোস্ট করে, message route করে।
- Presence Service: কে online/offline ট্র্যাক করে (Redis-এ)।
- Message Store (Cassandra): সব message persist করে।
- Message Queue (Kafka): decouple + reliable delivery।
- Push Notification Service: offline user-দের জন্য (APNs/FCM)।
Request flow (A থেকে B-কে message):
- User A তার Chat Server-এ WebSocket দিয়ে
send_messageপাঠায়। - Server message-কে Message Store-এ persist করে এবং A-কে "sent" ack দেয়।
- Server Presence Service-কে জিজ্ঞেস করে B online কিনা ও কোন server-এ আছে।
- B online হলে — তার Chat Server-এ message route হয়, B পায়, B-র app "delivered" ack পাঠায় → A সবুজ দুটো টিক দেখে।
- B offline হলে — message তার inbox queue-তে থাকে, আর Push Notification যায়।
- B চ্যাট খুলে message পড়লে read receipt যায় → A নীল টিক দেখে।
লক্ষ লক্ষ server-এর মধ্যে B কোনটায় connected আছে — সেটা জানতে একটা session registry (যেমন Redis: user_id → server_id) রাখা হয়। তাই A-র server জানে message কোন server-এ পাঠাতে হবে।
৬. গভীরে (Deep Dive)
Persistent Connection ও WebSocket
WebSocket হলো একটা স্থায়ী, দুই-মুখী connection — একবার খুললে server-ও client-কে যেকোনো সময় data push করতে পারে। সাধারণ HTTP-তে client বারবার request করে জিজ্ঞেস করতে হতো "নতুন message আছে?" (polling) — যা অপচয়। WebSocket-এ server নিজেই তৎক্ষণাৎ push করে দেয়। কিন্তু সমস্যা: প্রতিটি connection memory খায় আর সবসময় খোলা থাকে, তাই একটা server-এর connection সংখ্যা সীমিত (~65k পোর্ট সীমা ছাড়িয়ে tuning করতে হয়)। তাই হাজার হাজার connection server লাগে।
Presence (Online/Offline)
Presence মানে কে এখন online। Naive approach — প্রতিজনের status সবাইকে broadcast — তা স্কেল করে না। বাস্তবে Redis-এ প্রতি user-এর last_heartbeat রাখা হয়; client প্রতি 10-30 সেকেন্ডে একটা heartbeat পাঠায়। নির্দিষ্ট সময়ের মধ্যে heartbeat না এলে user offline ধরা হয়। আর status update শুধু সেইসব user-কে পাঠানো হয় যারা ওই user-এর সাথে active চ্যাট খুলে রেখেছে — সবাইকে নয়।
Group Chat Fan-out
Fan-out মানে একটা message group-এর সব member-এর কাছে ছড়িয়ে দেওয়া। ছোট group (যেমন 200 জন) হলে server প্রতিটি online member-এর কাছে copy push করে, offline member-দের queue-তে রাখে। কিন্তু group খুব বড় হলে এই fan-out ভারী হয়ে যায় — তখন message একবার store করে member-রা চাইলে pull করে নেয় (fan-out-on-read), যা WhatsApp-এর সাধারণ ছোট group-এর তুলনায় আলাদা strategy।
সব member-কে synchronously fan-out করতে গেলে একজন slow/offline user পুরো request আটকে দিতে পারে। তাই fan-out সবসময় asynchronous — message queue (Kafka)-এ ফেলে দিয়ে background worker delivery সামলায়।
৭. বটলনেক ও স্কেলিং
- Connection load: কোটি কোটি persistent connection — সমাধান হলো অনেক stateless gateway server + horizontal scaling, আর session registry দিয়ে routing।
- Message storage: ক্রমাগত বাড়ছে — সমাধান
chat_idদিয়ে sharding, আর পুরোনো message সস্তা cold storage-এ archive। - Hot groups: জনপ্রিয় বড় group — write hotspot তৈরি করে; queue + rate limiting + fan-out-on-read দিয়ে সামলানো।
- Presence storm: লক্ষ user একসাথে online হলে presence update বন্যা; Redis cluster + শুধু relevant subscriber-দের update দিয়ে কমানো।
- Push notifications: offline delivery-র জন্য FCM/APNs, যা decoupled queue থেকে চলে।
- Reliability: Kafka দিয়ে at-least-once delivery নিশ্চিত, আর message-এ unique id দিয়ে duplicate বাদ দেওয়া (idempotency)।
End-to-end encryption সম্পর্কে: WhatsApp end-to-end encryption ব্যবহার করে (Signal Protocol) — message sender-এর ফোনে encrypt হয়, শুধু receiver-এর ফোনে decrypt হয়, server শুধু encrypted blob route করে, পড়তে পারে না। তাই public key user table-এ রাখা হয়।
৮. সারসংক্ষেপ
WhatsApp ডিজাইনের হৃদয় হলো — persistent WebSocket দিয়ে real-time delivery, Redis দিয়ে presence ও session routing, NoSQL দিয়ে বিশাল message storage, queue দিয়ে reliable asynchronous fan-out, আর offline user-দের জন্য push notification। delivery status (sent/delivered/read) আসে ack message-এর মাধ্যমে, আর encryption নিশ্চিত করে privacy।
Interview-তে interviewer দেখতে চায় তুমি real-time delivery (WebSocket vs polling), offline handling, এবং fan-out trade-off নিয়ে স্পষ্ট ভাবতে পারো কিনা। "একটা message ঠিক কোন কোন ধাপে যায়" — এই flow পরিষ্কার বলতে পারলে অর্ধেক কাজ শেষ।
মিনি কুইজ
1. Real-time message push করার জন্য সবচেয়ে উপযুক্ত কোনটি?
2. User offline থাকলে message কোথায় থাকে?
3. Group chat-এ একটা message সব member-এর কাছে পৌঁছানোর প্রক্রিয়াকে কী বলে?