TGViewer
C# Geeks (.NET) C# Geeks (.NET) @csharpgeeks · 549 subscribers
Post #824 239
📩 سیستم پیامک در مقیاس بزرگ؛ چرا همه‌ی پیامک‌ها نباید در یک صف باشند؟ (Part1️⃣)

فرض کن ساعت ۵ عصر است.
یک سیستم بانکی باید هم‌زمان این پیام‌ها را ارسال کند:
🔐 پیامک OTP برای ورود کاربران
💳 پیامک برداشت و تراکنش مالی
📦 پیامک وضعیت سفارش
📢 پیامک تبلیغاتی
📰 پیامک اطلاع‌رسانی عمومی
حالا تصور کن یک کمپین تبلیغاتی شروع شده و ۷ میلیون پیامک وارد سیستم شده است.
اگر همه‌ی پیامک‌ها را داخل یک صف قرار دهیم، چه اتفاقی می‌افتد؟
[Marketing 1]
[Marketing 2]
...
[Marketing 7,000,000]
[OTP Login]

کاربر منتظر ورود به حسابش است، اما پیامک OTP او پشت میلیون‌ها پیامک تبلیغاتی گیر کرده.
از دید سیستم، صف هنوز در حال کار است.
اما از دید کاربر:
سیستم خراب است! 😐

اینجا باید از Priority Queue استفاده کنیم.

🎯 ایده‌ی اصلی Priority Queue
در صف معمولی، پیام‌ها بر اساس زمان ورود پردازش می‌شوند:
First In → First Out

اما در Priority Queue، هر پیام علاوه بر اطلاعات خودش، یک سطح اهمیت هم دارد:
{
"messageId": "msg-123",
"type": "OTP",
"priority": "Critical"
}

سیستم به‌جای اینکه فقط بپرسد:
کدام پیام زودتر وارد شده؟

می‌پرسد:
کدام پیام مهم‌تر است و باید زودتر پردازش شود؟

برای مثال:
Priority 0 → Critical
Priority 1 → High
Priority 2 → Normal
Priority 3 → Low

نکته‌ی مهم:
ءPriority Queue فقط ترتیب پردازش را مشخص می‌کند؛ ارسال واقعی همچنان به ظرفیت Provider، محدودیت شبکه و وضعیت مقصد وابسته است.


🧩 یک صف یا چند صف؟
برای پیاده‌سازی Priority Queue دو روش اصلی وجود دارد.
❗️روش اول: یک صف با Priority
در این روش همه‌ی پیام‌ها در یک Queue هستند، اما هر پیام Priority دارد:
Queue
├── Message A - Priority 3
├── Message B - Priority 1
├── Message C - Priority 2
└── Message D - Priority 0

ءConsumer باید پیام‌ها را بر اساس Priority دریافت کند.
✅مزیت:
مدیریت ساده‌تر
یک مسیر پردازش
مناسب برای سیستم‌های کوچک‌تر
❌مشکل:
کنترل ظرفیت هر سطح دشوارتر می‌شود.
ممکن است پیام‌های مهم وارد Consumerهای اشغال‌شده توسط پیام‌های کم‌اهمیت شوند.
رفتار واقعی به نوع Broker و تنظیمات Consumer وابسته است.
در RabbitMQ، Priority Queue وجود دارد؛ اما مستندات رسمی آن تأکید می‌کنند که اگر Consumer مقدار زیادی پیام را با prefetch دریافت کرده باشد، پیام Priority بالا ممکن است مجبور شود پشت پیام‌های کم‌اهمیتی که قبلاً به Consumer تحویل داده شده‌اند منتظر بماند.
پس این تنظیم مهم است:
Consumer Prefetch

اگر Prefetch بیش از حد بزرگ باشد، Broker تعداد زیادی پیام را زودتر به Consumer تحویل می‌دهد و فرصت اولویت‌بندی کاهش پیدا می‌کند.
❗️روش دوم: چند صف جداگانه
در سیستم‌های مهم‌تر، معمولاً Priorityها را به Queueهای جدا تقسیم می‌کنیم:
sms-critical
sms-high
sms-normal
sms-low

سپس Dispatcher تصمیم می‌گیرد از کدام صف پیام بردارد.
این مدل کنترل بیشتری می‌دهد و می‌توان برای هر صف Consumer یا ظرفیت جداگانه داشت.

⚠️ مشکل خطرناک: Starvation
فرض کن سیستم همیشه پیامک‌های Critical دریافت می‌کند.
Dispatcher هم همیشه این منطق را اجرا می‌کند:
تا وقتی Critical خالی نشده:
فقط Critical را پردازش کن

در این شرایط، پیامک‌های Low ممکن است هیچ‌وقت پردازش نشوند.
به این مشکل می‌گوییم:
Starvation

یعنی یک گروه از کارها دائماً منابع دریافت نمی‌کنند.
مثلاً:
Critical Queue:
همیشه پر است

Low Queue:
هیچ‌وقت نوبتش نمی‌رسد

این رفتار برای OTP شاید مناسب باشد، اما برای پیامک‌های عادی می‌تواند باعث شود:
پیام‌ها بیش از حد قدیمی شوند؛
کمپین‌ها بی‌ارزش شوند؛
هزینه‌ی نگهداری Queue افزایش پیدا کند؛
و Backlog دائماً رشد کند.

🛠 راه‌حل: Weighted Fair Scheduling
به‌جای اینکه همیشه فقط صف Critical را مصرف کنیم، برای هر صف سهمی تعیین می‌کنیم.
مثلاً:
Critical → 70%
High → 20%
Normal → 8%
Low → 2%

یعنی Dispatcher تلاش می‌کند بیشتر ظرفیت را به پیام‌های مهم بدهد، اما صف‌های دیگر را کاملاً گرسنه نگذارد.
یک مدل ساده:
در هر 100 پیام:

70 پیام از Critical
20 پیام از High
8 پیام از Normal
2 پیام از Low

⏳ ءAging؛ اولویت پیام قدیمی را افزایش بده
یک راه دیگر برای جلوگیری از Starvation، تکنیک Aging است.
ایده:
هرچه یک پیام بیشتر منتظر بماند، اولویت مؤثر آن بیشتر شود.

مثلاً:
Marketing Message:
Priority = Low

بعد از چند دقیقه:
Effective Priority = Normal

و اگر باز هم پردازش نشد:
Effective Priority = High

این فرمول فقط برای توضیح مفهوم است؛ در سیستم واقعی باید مراقب باشیم Aging باعث نشود پیام‌های قدیمی تبلیغاتی ناگهان OTPهای جدید را کنار بزنند.
برای همین معمولاً Priorityهای امنیتی و تراکنشی قوانین سخت‌گیرانه‌تری دارند.
More from @csharpgeeks
  1. Sep 22, 2026یه مدتی قراره از دنیای NET. فاصله بگیرم، چون وقتشه برم سربازی. راستش نمیدونم این مدت رو چج…
  2. Sep 20, 2026🔥 حالا مشکل اصلی: Alert Storm فرض کن Database از دسترس خارج شده. ۱۰۰ Pod داری. هر Pod می‌…
  3. Sep 20, 2026🚨 طراحی سیستم Monitoring و Alerting در یک سیستم بزرگ فرض کن ساعت ۳ صبح است. سیستم شما با…
  4. Sep 19, 2026#Engineering_Leadership تصمیم نگرفتن هم یک تصمیم است یه چیز عجیب توی تیم‌های مهندسی: گاهی…
  5. Sep 19, 2026☑ چک‌لیست آماده‌سازی تیم، فرایندها و زیرساخت برای توسعه با AI توجه: هیچ چک‌لیستی جهان‌شمول…
  6. Sep 19, 2026📌پایان یک انتظار طولانی: اعتبارسنجی ناهمگام (Async Validation) در NET 11.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →