RabbitMQ وبدائل قوائم الانتظار
RabbitMQ وبدائل قوائم الانتظار
تهيمن Kafka على نقاشات بث الأحداث، لكنك في بيئات الإنتاج الحقيقية ستصطدم بمواقف كثيرة تكون فيها Kafka الاختيار الخاطئ. إدراك متى تلجأ إلى RabbitMQ أو Amazon SQS أو غيرها من وسطاء قوائم الانتظار — وفهم لماذا يُفرّق المهندسون المحترفون بين مفهوم القائمة ومفهوم السجل — هو ما يميز من يصمم أنظمة تدوم عن من يُركّب تعقيداً لا مبرر له.
النموذج الذهني: قائمة مقابل سجل
المقايضة الأهم في هذا المجال هي معمارية لا تشغيلية. قائمة الرسائل (RabbitMQ, SQS, ActiveMQ) تُنمذج توزيع العمل: تبقى الرسالة حتى يُقرّها مستهلك واحد بالضبط، ثم تُحذف فور ذلك. أما السجل الموزع (Kafka, Kinesis, Pulsar) فيُنمذج سجلاً مرتباً ودائماً: يقرأ كل المستهلكين نفس الإزاحات وتبقى البيانات محفوظة بغض النظر عن الإقرارات.
- استخدم القائمة عندما: تحتاج تنفيذ المهام مرة واحدة بالضبط بواسطة عامل واحد — معالجة الطلبات، إصدار الفواتير، إرسال البريد الإلكتروني، استدعاءات API غير المتزامنة، توزيع المهام على مستهلكين متباينين.
- استخدم السجل عندما: تحتاج أنظمة مستقلة متعددة إلى نفس الأحداث، أو تحتاج إمكانية الإعادة — قنوات التحليلات، سجلات التدقيق، التقاط تغييرات البيانات (CDC)، قنوات ميزات التعلم الآلي.
معمارية RabbitMQ في 60 ثانية
تُطبّق RabbitMQ بروتوكول AMQP 0-9-1. يُرسل المنتجون إلى بورصة (exchange)؛ تُوجّه البورصة الرسائل إلى قائمة أو أكثر عبر روابط (bindings). يسحب المستهلكون من القوائم ويُرسلون basic.ack أو basic.nack صراحةً. تُحذف الرسائل المُقرّة من الوسيط. أربعة أنواع للبورصات تغطي معظم أنماط التوجيه:
- direct — التوجيه بمطابقة دقيقة لمفتاح التوجيه (قوائم العمل، توزيع المهام)
- topic — مفاتيح توجيه ذات أحرف بديلة (
payments.#,*.critical) - fanout — بث لجميع القوائم المربوطة (الإشعارات، إبطال التخزين المؤقت)
- headers — توجيه بناءً على خصائص ترويسة الرسالة (نادر الاستخدام ويُضيف تكلفة)
تشغيل RabbitMQ في الإنتاج
المسار الأنسب في Kubernetes هو RabbitMQ Cluster Operator. عنقود من ثلاثة عقد بقوائم الأصوات (quorum queues) هو الحد الأدنى للإنتاج — حلّت قوائم الأصوات محل القوائم المعكوسة الكلاسيكية منذ الإصدار 3.8 وتُقدّم نسخاً متماثلاً قائماً على Raft دون فقدان بيانات عند الفشل.
vm_memory_high_watermark.relative = 0.4 على عقدة 4 جيجابايت، تُطلق العتبة عند 1.6 جيجابايت. اضبطها على 0.6 وتأكد من أن المستهلكين يستنزفون القائمة أسرع مما ينتج المنتجون، وإلا ستضغط الضغط على الوسيط بأكمله عند كل ارتفاع في حركة البيانات.
أعلن عن Dead-Letter Exchange (DLX) لكل قائمة تُنجز عملاً. الرسائل التي تتجاوز x-max-delivery-count أو مدة صلاحيتها تُوجَّه إليه تلقائياً، حيث يتولى مستهلك منفصل أو خط مراقبة فحص الإخفاقات دون فقدانها.
Amazon SQS — متى تفوز الخدمة المُدارة
تُلغي SQS كل عمليات الوسيط. لا عناقيد تُحجم، ولا نسخ متماثل بالأصوات تضبطه، ولا عتبات ذاكرة تراقبها. المقايضة هي مجموعة ميزات محدودة ونموذج تسليم "مرة واحدة على الأقل" مع حجم رسالة أقصاه 256 كيلوبايت. نوعان من القوائم يغطيان غالبية الحالات:
- القائمة المعيارية: معدل نقل شبه لا محدود، تسليم مرة واحدة على الأقل، ترتيب تقديري. مناسبة لمعظم أعباء المهام غير المتزامنة التي صُمّمت أصلاً مع مراعاة idempotency.
- قائمة FIFO: معالجة مرة واحدة بالضبط داخل مجموعة الرسائل، 3000 رسالة/ثانية مع التجميع (300 دونه). استخدمها حين يهم الترتيب داخل مجموعة منطقية واحدة — مثلاً انتقالات حالة متسلسلة لمعرّف طلب واحد.
RedrivePolicy على قائمة رسائل ميتة بعد 3-5 محاولات، وراقب ApproximateNumberOfMessagesNotVisible (قيد الرحلة) وApproximateAgeOfOldestMessage بوصفهما مؤشري أداء رئيسيين لـ SQS.
إطار اتخاذ القرار: أي الأدوات تختار؟
يفكّر المهندسون المتمرسون في هذه المحاور في آنٍ واحد عند تقييم تقنية وسيط لحمل عمل جديد:
- دلالات التسليم: هل تحتاج مرة واحدة بحدٍّ أقصى (fire-and-forget)، أم مرة واحدة على الأقل (SQS standard, Kafka, RabbitMQ)، أم مرة واحدة فعلياً (SQS FIFO، منتج Kafka idempotent مع المعاملات)؟
- نموذج المستهلك: المستهلكون المتنافسون (عامل واحد من مجموعة يعالج كل رسالة) يُفضّل القوائم. مجموعات مستهلكين مستقلة تحتاج نفس الأحداث تُفضّل السجلات.
- الاحتفاظ بالرسائل: تحذف القوائم الرسائل المُقرّة؛ تحتفظ السجلات بالبيانات ساعات إلى الأبد. إن احتاج فريق التحليلات إلى أحداث الأمس التي استهلكتها خدمة الدفع بالفعل، فأنت تحتاج سجلاً.
- السطح التشغيلي: تتطلب RabbitMQ إدارة عنقود حقيقية (نسخ بالأصوات، ضبط الذاكرة، نوافذ الترقية، تناوب الشهادات). تُلغي SQS/SNS كل ذلك مقابل الارتباط بـ AWS. تتطلب Kafka أكبر استثمار تشغيلي لكنها تُقدّم الإنتاجية الأعلى وإمكانية الإعادة.
- الإنتاجية مقابل التعقيد: تتعامل SQS مع ملايين الرسائل في الثانية لكل قائمة دون أي عمليات. تصل RabbitMQ إلى ذروتها عند 50-100 ألف رسالة/ثانية لكل عنقود قبل أن تحتاج التجزئة. تتعامل Kafka مع الملايين في الثانية لكنها تُضيف إدارة الأقسام وإعادة التوازن لمجموعات المستهلكين وتعقيد سجل المخطط.
إشارات المراقبة التي تهم فعلاً
لـ RabbitMQ، صدّر المقاييس عبر إضافة Prometheus (rabbitmq_prometheus) وأنشئ تنبيهات على: rabbitmq_queue_messages_ready تنمو دون توقف (تأخر المستهلك)، وrabbitmq_queue_messages_unacked ترتفع (المستهلكون متوقفون)، وrabbitmq_node_mem_used تقترب من العتبة. لـ SQS، راقب ApproximateAgeOfOldestMessage — القائمة التي تستنزف ببطء هي في الغالب مشكلة مستهلك، لا مشكلة بنية تحتية.