🎯 در System Design اول Kafka و RabbitMQ را انتخاب نکن!
فرض کنید کاربر روی دکمه ثبت سفارش کلیک میکند.
در چند ثانیه آینده ممکن است دهها اتفاق مختلف در سیستم رخ دهد:
🟢 پرداخت سفارش
🟢 بررسی و کسر موجودی
🟢 ارسال Email
🟢 ارسال SMS
🟢 ثبت امتیاز کاربر
🟢 بروزرسانی Analytics
🟢 ارسال Event برای Recommendation Engine
🟢 بهروزرسانی سیستم Loyalty
حالا یک سؤال مهم:
آیا همه این عملیات باید قبل از اینکه به کاربر پاسخ
200 OK بدهیم، انجام شوند؟اگر جواب «بله» باشد، خیلی سریع به یک مشکل معماری میرسیم.
🔴 اشتباه رایج
ممکن است چنین Flowای طراحی کنیم:
Client
↓
Order Service
↓
Payment Service
↓
Inventory Service
↓
Email Service
↓
SMS Service
↓
Analytics Service
↓
Recommendation Service
↓
Response
در ظاهر ساده است.
اما حالا فرض کنید:
Payment → 200msInventory → 100msEmail → 500msSMS → 800msAnalytics → 1sRecommendation → 2sکاربر برای انجام یک عملیات ساده باید منتظر مجموع این وابستگیها بماند.
بدتر از آن، اگر فقط Recommendation Service از دسترس خارج شود، آیا واقعاً باید ثبت سفارش کاربر هم Fail شود؟
احتمالاً نه.
اینجا یک مفهوم بسیار مهم وارد طراحی میشود:
Business Criticality
یعنی:
اگر این عملیات انجام نشود، آیا Business Rule اصلی نقض میشود؟
🟢 عملیات Business-Critical
مثلاً:
Payment
اگر پرداخت انجام نشود، نمیتوانیم سفارش را به وضعیت Paid ببریم.
یا:
Inventory
اگر آخرین واحد محصول همزمان به دو نفر فروخته شود، یک Business Invariant نقض شده است.
بنابراین این عملیاتها معمولاً بخشی از Critical Path هستند.
Create Order
↓
Check Inventory
↓
Reserve Stock
↓
Process Payment
↓
Order Confirmed
در این قسمت، Consistency و نتیجه قطعی عملیات اهمیت زیادی دارد.
🔵 اما همه چیز Business-Critical نیست
فرض کنید سفارش با موفقیت ثبت شده است.
حالا باید:
📧 ءEmail ارسال شود.
📱 ءSMS ارسال شود.
📊 اطلاعات Analytics ثبت شود.
⭐️ امتیاز کاربر محاسبه شود.
🤖 ءRecommendation Engine از خرید جدید مطلع شود.
آیا اگر Email Service برای ۳۰ ثانیه Down باشد، باید Order هم Fail شود؟
معمولاً نه.
این عملیاتها را میتوان از مسیر اصلی خارج کرد.
در اینجا Asynchronous Processing میتواند انتخاب مناسبتری باشد.
اما اینجا یک نکته مهم وجود دارد...
وقتی میگوییم:
«این را Async کنیم»
هنوز نگفتهایم Kafka یا RabbitMQ.
چون انتخاب Broker باید بعد از مشخص شدن Communication Pattern انجام شود.
🐇 چه زمانی RabbitMQ منطقیتر است؟
فرض کنید بعد از ثبت سفارش، یک Task داریم:
SendOrderConfirmationEmail
این Message باید توسط یک Consumer پردازش شود.
ما الزاماً به تاریخچه بلندمدت Eventها، Replay کردن میلیونها Event یا Stream Processing نیاز نداریم.
هدف ما بیشتر این است:
یک Message را قابلاعتماد به Consumer برسانیم و آن را پردازش کنیم.
در چنین سناریویی، یک Message Broker مانند RabbitMQ میتواند انتخاب مناسبی باشد.
ءConsumer میتواند Message را پردازش کند و در صورت موفقیت
Ack بدهد.🟣 ءKafka چه زمانی معنا پیدا میکند؟
حالا سناریوی دیگری را تصور کنید.
وقتی Order ایجاد شد، میخواهیم چندین سیستم مستقل از آن مطلع شوند:
OrderCreated
│
▼
Kafka
│
┌────┼────┬───────────┐
▼ ▼ ▼ ▼
CRM Analytics Recommendation Loyalty
حالا هر Consumer میتواند جریان Eventهای خودش را مستقل دنبال کند.
ءAnalytics ممکن است Event را مصرف کند.
ءRecommendation هم همان Event را مصرف کند.
ءLoyalty هم همان Event را مصرف کند.
و در سناریوهایی که نیاز به نگهداری Eventها و Replay وجود دارد، Kafka مدل متفاوتی نسبت به یک Message Queue سنتی ارائه میکند.
بنابراین سؤال درست این نیست:
«Kafka بهتر است یا RabbitMQ؟»
سؤال درست این است:
«من دقیقاً چه نوع Communication Patternای دارم؟»
⚠️ یک اشتباه خطرناکتر
حتی اگر تصمیم بگیریم عملیات را Async کنیم، هنوز کار تمام نشده است.
مثلاً:
Order DB
↓
Publish Event
اگر Order در Database Commit شود ولی Publish کردن Event شکست بخورد چه؟
DB Commit ✅
Publish Event ❌
حالا Order ایجاد شده، اما هیچ Consumerای از آن خبر ندارد.
اینجاست که الگوهایی مثل Transactional Outbox اهمیت پیدا میکنند.