Message Queues & Event Streaming
Message Queue কী?
ধরুন আপনি Swiggy তে খাবার order দিলে। তৎক্ষণাৎ screen এ আসে "Order Confirmed!" — আপনি phone রেখে দিলে। কিন্তু পেছনে কী হচ্ছে? Restaurant কে notification গেলো, delivery partner assign হলো, payment process হলো, invoice তৈরি হলো। এই সব কাজ আপনার জন্য wait করছে না।
এটাই Async Messaging। Sync মানে — আপনি কাজ দিলে, সে শেষ করলেন, তারপর next step। Async মানে — আপনি কাজ দিলে, সে নিজের সময়ে করবেন, আপনি এগিয়ে যান।
SYNC ❌ ব্লকিং
Order দিন → Email পাঠাও (wait) → SMS পাঠাও (wait) → Inventory update (wait) → Response। সব শেষ না হওয়া পর্যন্ত user আটকে।
ASYNC ✅ নন-ব্লকিং
Order দিন → Queue তে message রাখুন → "Order Confirmed!" return। Background এ Email, SMS, Inventory সব parallel হয়।
DEFINITION — Message Queue কী?
- Message Queue হলো একটা middleware — দুটো service এর মাঝখানে buffer হিসেবে কাজ করে।
- Producer — message পাঠায় (যে কাজ দেয়)।
- Queue — message গুলো সংরক্ষণ করে (buffer/storage)।
- Consumer — queue থেকে message নেয় এবং নিজের গতিতে process করে।
- Decoupled — Producer আর Consumer একে অপরকে চেনে না, সরাসরি কথা বলে না।
কেন Async Messaging দরকার?
1. DECOUPLING
Service B down হলেও Service A চলতে পারে। Message queue তে জমা থাকবেন, B উঠলে process করবেন। Services একে অপরের উপর directly depend করে না।
2. TRAFFIC SPIKE BUFFER
হঠাৎ ১০,০০০ order আসলে queue buffer হিসেবে কাজ করে। Consumer নিজের গতিতে process করে। System overload হয় না।
3. RETRY LOGIC
Consumer fail করলেন message queue তে থাকে। Retry করা যায় — data loss নেই। Email service crash হলেও email টা পরে পাঠানো সম্ভব।
4. MICROSERVICES
Microservices architecture এ services loosely coupled থাকে। Queue হলো তাদের communication bridge — directly call না করে message দিয়ে কথা বলে।
Real Example — E-Commerce Order Flow
User checkout করলো → Payment Service payment নিলো → Queue তে order_placed event publish করলো।
Queue থেকে parallel এ চারটা service কাজ শুরু করলো:
- 📧 Email Service — confirmation email পাঠালো
- 📱 SMS Service — OTP/update পাঠালো
- 📦 Inventory Service — stock কমালো
- 📊 Analytics Service — event log করলো
User কে শুধু Payment Service এর response দরকার। বাকি সব async — user দেখে না, জানে না, অপেক্ষা করে না।
Message Queue Patterns
Pattern 1 — Point-to-Point (Queue Model)
একটা message শুধু একজন consumer পায়। Task queue এর মতো — কেউ একজন কাজটা নিয়ে করে।
উদাহরণ: Image resize task queue — ১টা worker একটা image নেয়, process করে, next।
Pattern 2 — Publish-Subscribe (Topic / Fan-out)
একটা message সব subscribers পায়। এটা broadcast — একজন বলে, সবাই শোনে।
উদাহরণ: Kafka topic — সব Consumer Group independently same message পড়তে পারে।
Apache Kafka — Event Streaming Platform
LinkedIn এ তৈরি, এখন Uber, Netflix, Airbnb সহ হাজারো company ব্যবহার করে। প্রতিদিন trillions of events process করে। Kafka শুধু message queue না — এটা distributed event streaming platform।
Kafka Key Terms — জানতেই হবে
- Topic— message এর category। যেমন "order_placed", "user_signup"।
- Partition — Topic কে parallel শাখায় ভাগ করে। বেশি partition = বেশি throughput।
- Offset — Partition এর প্রতিটা message এর unique index। Consumer এখানে থেকে পড়ে।
- Producer — Topic এ message লেখে।
- Consumer Group — একদল consumer মিলে একটা topic process করে। প্রতিটা partition একজন consumer এ যায়।
- Broker — Kafka server। Cluster এ অনেক broker থাকে।
- Replication Factor — প্রতিটা partition কতটা broker এ copy থাকবেন (fault tolerance)।
Kafka Architecture
Kafka's Unique Power — এটাই পার্থক্য
- Message Replay — পুরনো message আবার পড়া যায়। Consumer নতুন আসলেও পুরো history process করতে পারে।
- Multiple Consumer Groups — একই topic থেকে Email service আর Analytics service independently পড়তে পারে — একজন আরেকজনকে affect করে না।
- Durable Storage — Message disk এ থাকে, days/weeks পর্যন্ত। Consumer down থাকলেও data নষ্ট হয় না।
RabbitMQ — Traditional Message Broker
AMQP protocol ব্যবহার করে। Complex routing, explicit acknowledgment, Dead Letter Queue — এগুলো RabbitMQ এর specialty। Push-based model — broker consumer কে message push করে।
RabbitMQ Key Concepts
- Exchange — Message কোন queue তে যাবেন তা decide করে। Types: Direct, Topic, Fanout, Headers।
- Queue — Message store করে। Consumer এখান থেকে নেয়।
- Binding — Exchange আর Queue এর মধ্যে connection rule।
- ACK (Acknowledgment) — Consumer message সফলভাবে process করলেন broker কে জানায় → broker message delete করে।
- NACK + DLQ (Dead Letter Queue) — Consumer fail করলেন NACK পাঠায় → বারবার fail হলে message Dead Letter Queue তে যায়।
| Feature | Kafka | RabbitMQ |
|---|---|---|
| Model | Event Log (Pull-based) | Message Queue (Push-based) |
| Message Retention | Days/weeks — replay সম্ভব | ACK এর পর delete |
| Throughput | Millions/sec | Thousands/sec |
| Message Replay | হ্যাঁ ✓ | না ✗ |
| Complex Routing | Topic/Partition based | Exchange types (flexible) |
| ACK/NACK + DLQ | Offset commit | Explicit ACK/NACK + DLQ |
| Best For | Real-time streaming, analytics | Task queues, job processing |
Code Examples — হাতে-কলমে দেখুন
Kafka — Python Producer & Consumer
from kafka import KafkaProducer, KafkaConsumer
import json
# ── PRODUCER: Order Service ──────────────────────────────────────────────
producer = KafkaProducer(
bootstrap_servers='localhost:9092',
value_serializer=lambda v: json.dumps(v).encode('utf-8')
)
def place_order(order_id, user_id, items):
event = {
"order_id": order_id,
"user_id": user_id,
"items": items,
"status": "placed"
}
# topic: "order_placed" এ message publish করুন
producer.send('order_placed', value=event)
producer.flush()
print(f"✅ Order {order_id} event published to Kafka")
place_order("ORD-001", "USR-42", [{"item": "Biryani", "qty": 2}])
# ── CONSUMER: Email Service ───────────────────────────────────────────────
consumer = KafkaConsumer(
'order_placed',
bootstrap_servers='localhost:9092',
group_id='email-service-group', # Consumer Group ID
auto_offset_reset='earliest',
value_deserializer=lambda m: json.loads(m.decode('utf-8'))
)
print("📧 Email Service listening for order events...")
for message in consumer:
order = message.value
print(f"Sending confirmation email for order: {order['order_id']}")
# send_email(order['user_id'], order['order_id'])
# offset automatically commit হয় — message processed হলেRabbitMQ — Node.js Publisher & Worker
const amqp = require('amqplib');
// ── PUBLISHER ────────────────────────────────────────────────────────────
async function publishImageTask(imageUrl) {
const connection = await amqp.connect('amqp://localhost');
const channel = await connection.createChannel();
const queue = 'image_resize';
await channel.assertQueue(queue, { durable: true }); // queue crash এ survive করে
const task = JSON.stringify({ imageUrl, width: 800, height: 600 });
channel.sendToQueue(queue, Buffer.from(task), { persistent: true });
console.log("📤 Task queued:", imageUrl);
await channel.close();
await connection.close();
}
publishImageTask('https://cdn.example.com/photo-001.jpg');
// ── WORKER (Consumer) ─────────────────────────────────────────────────────
async function startWorker() {
const connection = await amqp.connect('amqp://localhost');
const channel = await connection.createChannel();
const queue = 'image_resize';
await channel.assertQueue(queue, { durable: true });
channel.prefetch(1); // একটা message process শেষ না হলে পরেরটা নেবে না
console.log("🔧 Worker listening for image tasks...");
channel.consume(queue, async (msg) => {
const task = JSON.parse(msg.content.toString());
try {
console.log(`Processing: ${task.imageUrl}`);
await resizeImage(task.imageUrl, task.width, task.height); // actual work
channel.ack(msg); // ✅ সফল → broker কে জানাও, message delete হবে
console.log("✅ Image processed successfully");
} catch (error) {
console.error("❌ Failed:", error.message);
channel.nack(msg, false, false); // ❌ fail → requeue: false → DLQ তে যাবেন
}
});
}
startWorker();Dead Letter Queue Setup
const amqp = require('amqplib');
async function setupDLQ() {
const connection = await amqp.connect('amqp://localhost');
const channel = await connection.createChannel();
// 1. Dead Letter Exchange তৈরি করুন
await channel.assertExchange('dlx_exchange', 'direct', { durable: true });
// 2. Dead Letter Queue তৈরি করুন
await channel.assertQueue('dead_letter_queue', { durable: true });
await channel.bindQueue('dead_letter_queue', 'dlx_exchange', 'failed');
// 3. Main queue — DLX config সহ
await channel.assertQueue('image_resize', {
durable: true,
arguments: {
'x-dead-letter-exchange': 'dlx_exchange', // fail হলে এখানে যাবেন
'x-dead-letter-routing-key': 'failed',
'x-message-ttl': 30000, // 30 sec এর মধ্যে process না হলে DLQ
}
});
console.log("✅ DLQ setup complete");
// এখন যেকোনো nack(msg, false, false) → dlx_exchange → dead_letter_queue
await connection.close();
}
setupDLQ();Kafka vs RabbitMQ vs AWS SQS — কোনটা কখন?
| Tool | Best For | Throughput | Complexity | Managed? |
|---|---|---|---|---|
| Apache Kafka | Real-time analytics, event streaming | Millions/sec | High | Self-hosted / Confluent Cloud |
| RabbitMQ | Task queues, complex routing | Thousands/sec | Medium | Self-hosted |
| AWS SQS | Simple task queue, decoupling | High | Low | Fully managed ✓ |
| AWS SNS | Pub/Sub fan-out notifications | High | Low | Fully managed ✓ |
| Redis Streams | Lightweight streaming, low latency | High | Low | Self-hosted |
Quick Decision Guide
- Kafka বেছে নাও যখন — real-time analytics, event replay দরকার, millions of events/sec, multiple teams same data consume করবেন।
- RabbitMQ বেছে নাও যখন — complex routing logic, task queue, ACK/retry behavior দরকার, throughput কম কিন্তু reliability বেশি।
- AWS SQS বেছে নাও যখন — AWS already ব্যবহার করছো, simple decoupling দরকার, infrastructure manage করতে চাও না।
- Redis Streams বেছে নাও যখন — already Redis আছে, lightweight streaming, low latency দরকার।
Interview Prep — এই প্রশ্নগুলো আসবেনই
Q1: Kafka At-Least-Once vs Exactly-Once Delivery কী?
- At-Least-Once — Message কমপক্ষে একবার deliver হবে। Consumer crash করে re-process করলেন duplicate হতে পারে। Default behavior।
- At-Most-Once — Message হয়তো পাবেন, হয়তো পাবেন না। Data loss সম্ভব।
- Exactly-Once — Message exactly একবার deliver হবে। Idempotent producer + transactional consumer দিয়ে achieve করা যায়। Performance overhead আছে।
- Interview answer: "Production এ আমি at-least-once ব্যবহার করি এবং consumer কে idempotent বানাই — duplicate message আসলেও same result হয়।"
Q2: Kafka Partition কীভাবে Throughput বাড়ায়?
- একটা Topic কে N টা Partition এ ভাগ করলেন N টা Consumer Group member parallel এ পড়তে পারে।
- Partition = Parallelism unit। 10 partition → 10 consumer same topic এ parallel কাজ করতে পারে।
- Key-based partitioning — same order_id এর সব event একই partition এ → ordering guarantee।
- Rule: Consumer Group এ Consumer সংখ্যা ≤ Partition সংখ্যা। বেশি consumer থাকলে idle থাকবেন।
Q3: Message Queue vs Direct API Call — কখন কোনটা?
- — Immediate response দরকার (payment confirmation)
- — Strong consistency দরকার
- — Simple request-response pattern
- — Result immediately দরকার নেই (email, notification)
- — Service গুলো independent থাকুক
- — Traffic spike handle করতে হবে
- — Retry/fault tolerance দরকার
Q4: Dead Letter Queue কী কাজ করে?
- যে message বারবার process করতে গিয়ে fail হয় — সেটা main queue থেকে সরিয়ে Dead Letter Queue (DLQ) তে রাখা হয়।
- DLQ তে message থাকলে engineer manually investigate করতে পারে — কেন fail হলো।
- "Poison message" problem সলভ করে — একটা bad message পুরো queue আটকে না রাখে।
- Real use case: Invalid payment data → 3 বার retry → DLQ → Alert → Manual fix → Reprocess।
SUMMARY — আজকে যা শিখলাম
| Concept | এক লাইনে |
|---|---|
| Message Queue | Services এর মাঝখানে async buffer — decoupling এর হাতিয়ার |
| Point-to-Point | একটা message শুধু একজন consumer পায় — task queue |
| Pub/Sub | একটা message সব subscribers পায় — broadcast / fan-out |
| Kafka | Event streaming, replay সম্ভব, millions/sec, multiple Consumer Groups |
| RabbitMQ | Traditional broker, complex routing, ACK/NACK, DLQ support |
| Dead Letter Queue | Repeatedly fail message আলাদা রাখে — investigate করা যায় |
| Consumer Group | Multiple consumers coordinate করে একটা topic parallel process করে |