طلبات المستخدمين كانت تضيع: كيف أنقذتنا “طوابير الرسائل” (Message Queues) من جحيم فقدان البيانات؟

يا جماعة الخير، السلام عليكم ورحمة الله. معكم أخوكم أبو عمر.

خلوني أحكيلكم قصة صارت معي ومع الفريق قبل كم سنة، قصة ما بنساها، علّمتني درس من ذهب. كنا وقتها شغالين على منصة تجارة إلكترونية جديدة، وكنا مبسوطين كثير ومتوقعين إطلاق ناجح. قبل الإطلاق بأسبوع، قررنا نعمل “اختبار ضغط” حقيقي، وحضرنا حالنا ليوم “الجمعة البيضاء” المنتظر. جهزنا عروضنا، وأطلقنا حملاتنا التسويقية، وكنا قاعدين نراقب الشاشات زي الصقور.

وبدأت المعركة. أول ساعة، الأمور كانت “عال العال”. الطلبات بتنزل، والمستخدمين مبسوطين. فجأة، وبدون سابق إنذار، بدأت الشكاوى توصل على خدمة العملاء: “دفعت وما وصلني تأكيد!”، “طلبي مش موجود في حسابي!”، “الموقع علّق وأخذ فلوسي!”.

في غرفة العمليات، كنا زي اللي انصدم بسيارة. حالة فوضى عارمة، و”انعجقنا عجقة” ما يعلم فيها إلا ربنا. السيرفرات ما وقعت، لكن البيانات كانت بتضيع! اكتشفنا إنه مع الضغط الهائل، خدمة معالجة الطلبات كانت بتوصلها آلاف الطلبات في نفس الثانية، فكانت يا إما بتعلق، يا إما قاعدة البيانات بترفض الاتصالات الجديدة، والأسوأ من هيك، كانت بتعمل إعادة تشغيل تلقائي، وكل الطلبات اللي كانت في الذاكرة (In-Memory) وقتها… راحت في مهب الريح. شعور بالعجز لا يوصف، ويا ريت اللي جرى ما كان.

هذيك الليلة ما نمنا، وقررنا إنه هذا الأسلوب في بناء الأنظمة ما بنفع. لازم نلاقي حل يخلي النظام صامد وموثوق، حتى لو “الدنيا قامت وقعدت”. ومن هنا، بدأت رحلتنا مع عالم الـ Message Queues أو “طوابير الرسائل”.

ما هي طوابير الرسائل؟ قصة ساعي البريد

قبل ما ندخل في التعقيدات التقنية، خليني أبسطلكم الفكرة. تخيل إنك بدك تبعث رسالة مهمة لشخص في مدينة ثانية. في عالمنا القديم (قبل طوابير الرسائل)، كان لازم تروح بنفسك وتسلمها للشخص وتستنى منه الرد. لو الطريق كان زحمة، أو الشخص مش موجود، رح تضطر تستنى، وممكن تضيع وقت طويل أو حتى تفشل في التسليم.

طوابير الرسائل هي ببساطة “مكتب البريد” في عالم البرمجيات. أنت (الخدمة الأولى أو الـ Producer) بتروح على مكتب البريد، بتسلم رسالتك (البيانات أو الطلب)، وبتاخذ وصل وبتروح تكمل شغلك. مكتب البريد (الـ Message Queue أو الـ Broker) بحافظ على رسالتك بأمان في طابور. بعدين، بيجي ساعي البريد (الخدمة الثانية أو الـ Consumer) وبياخذ الرسائل من الطابور بالترتيب، وبيوصلها براحته وبالسرعة اللي بيقدر عليها.

الفكرة بسيطة، لكن عبقرية! أنت كمُرسل ما عاد يهمك متى رح توصل الرسالة بالضبط، المهم إنك متأكد إنها في أمان ورح يتم التعامل معها. “خلص، حطيتها في البريد وارتاح”.

المكونات الأساسية في اللعبة

  • المنتج (Producer): هو الجزء من نظامك اللي بينشئ الرسالة. في قصتنا، كان المفروض يكون هو الـ API اللي بيستقبل طلب الشراء من المستخدم.
  • الطابور (Queue): هو الصندوق اللي بتتخزن فيه الرسائل بالترتيب (First-In, First-Out). هو الذاكرة الصامدة اللي بتحفظ بياناتك من الضياع.
  • المستهلك (Consumer): هو العامل أو “ساعي البريد” اللي بيسحب الرسائل من الطابور واحدة تلو الأخرى وبيقوم بمعالجتها (مثلاً: تسجيل الطلب في قاعدة البيانات، إرسال إيميل تأكيد، خصم المنتج من المخزون).

كيف أنقذتنا طوابير الرسائل من الجحيم؟

لما طبقنا هذا المفهوم، تغير كل شيء. النظام تحول من بيت من ورق إلى قلعة حصينة. وهذه هي الأسباب الرئيسية:

1. الفصل بين المكونات (Decoupling)

صار الـ API اللي بيستقبل الطلبات ما بيعرف أي شيء عن عملية معالجة الطلب. مهمته الوحيدة هي إنه يستقبل الطلب، يتأكد إنه سليم، ويرميه في الطابور. خلص. هيك صار “كل واحد في حاله”، والخدمات صارت مستقلة. لو خدمة معالجة الطلبات وقعت أو احتجنا نحدّثها، الـ API بضل شغال وبيستقبل طلبات وبحطها في الطابور بدون أي مشكلة.

2. الموثوقية والصمود (Reliability & Durability)

وهذا هو مربط الفرس. الرسالة بتضل محفوظة في الطابور حتى يقوم المستهلك بسحبها والتأكيد على أنه عالجها بنجاح (ما يسمى بالـ Acknowledgement أو `ack`). لو المستهلك سحب رسالة وبدأ يعالجها وفجأة “مات” (صارله crash)، الطابور ما بيحذف الرسالة، بل بيرجعها للطابور مرة ثانية عشان مستهلك ثاني (أو نفس المستهلك لما يرجع يشتغل) يعالجها. وداعاً لفقدان البيانات! ما بتضيع طوشة بحارة هادية.

3. امتصاص الصدمات وتوزيع الأحمال (Load Leveling)

تذكروا مشكلة الـ 1000 طلب في الثانية؟ مع وجود الطابور، هاي بطلت مشكلة. الطابور صار زي الإسفنجة اللي بتمتص كل الضغط. بتيجي 1000 رسالة، بتتصف في الطابور بهدوء. في الجهة الثانية، ممكن يكون عندي 5 أو 10 “مستهلكين” شغالين على مهلهم، كل واحد بيسحب رسالة وبيعالجها بالسرعة اللي بيقدر عليها بدون ما يضغط على قاعدة البيانات. الطابور حول لنا الفوضى العارمة إلى عملية منظمة ومستقرة.

4. قابلية التوسع (Scalability)

صار التوسع أسهل بكثير. لو لاحظنا إنه الطابور بدأ يطول والرسائل بتتراكم، شو الحل؟ ببساطة، بنشغل “مستهلكين” زيادة! بدل 5، بنخليهم 20 أو 50. كل مستهلك جديد رح يبدأ يسحب من نفس الطابور ويساعد في تفريغه. العملية مرنة جداً وما بتحتاج تغييرات معقدة في الكود.

خلينا نشوف الكود يا جماعة (مثال بـ Python و RabbitMQ)

الكلام النظري حلو، بس خلينا نشوف تطبيق عملي. رح نستخدم RabbitMQ، وهو واحد من أشهر أنظمة طوابير الرسائل، مع لغة Python.

أولاً: المنتج (producer.py) – اللي بيرسل الطلب

هذا الكود بيمثل الواجهة اللي بتستقبل طلب الشراء وبترميه في طابور اسمه `order_queue`.


import pika
import json

# الاتصال بـ RabbitMQ
# لو RabbitMQ على سيرفر ثاني، غير 'localhost' لعنوان السيرفر
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

# نتأكد إنه الطابور موجود، ولو مش موجود بننشئه
# durable=True بتخلي الطابور يضل موجود حتى لو السيرفر عمل إعادة تشغيل
channel.queue_declare(queue='order_queue', durable=True)

# بيانات الطلب اللي بدنا نرسلها (عادة بتكون جاية من طلب HTTP)
order_data = {
    'user_id': 123,
    'product_id': 'prod-5544',
    'quantity': 2,
    'price': 99.99
}

# إرسال الرسالة للطابور
# delivery_mode=2 بتخلي الرسالة نفسها "صامدة" (persistent)
channel.basic_publish(
    exchange='',
    routing_key='order_queue',
    body=json.dumps(order_data),
    properties=pika.BasicProperties(
        delivery_mode=2,  # make message persistent
    ))

print(f" [x] تم إرسال الطلب: {order_data}")

connection.close()

ثانياً: المستهلك (consumer.py) – اللي بيعالج الطلب

هذا الكود بيمثل الخدمة اللي شغالة في الخلفية، بتستنى الطلبات وبتعالجها.


import pika
import time
import json

# الاتصال بـ RabbitMQ
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

channel.queue_declare(queue='order_queue', durable=True)
print(' [*] في انتظار الطلبات. للخروج اضغط CTRL+C')

# دالة المعالجة اللي رح يتم استدعاؤها لكل رسالة
def callback(ch, method, properties, body):
    order_data = json.loads(body)
    print(f" [x] تم استلام طلب جديد: {order_data}")
    
    # محاكاة لعملية معالجة تأخذ وقت (مثل الكتابة في قاعدة البيانات)
    print(" [.] جاري معالجة الطلب...")
    time.sleep(2) # ننتظر ثانيتين
    
    print(" [x] تم معالجة الطلب بنجاح!")
    
    # أهم خطوة: إرسال تأكيد (acknowledgement)
    # هذا بيخبر RabbitMQ إنه الرسالة تمت معالجتها بنجاح وممكن حذفها من الطابور
    ch.basic_ack(delivery_tag=method.delivery_tag)

# هذا السطر بيضمن إنه المستهلك ما يسحب رسالة جديدة إلا لما يخلص من الحالية
channel.basic_qos(prefetch_count=1)

# ربط دالة المعالجة مع الطابور
channel.basic_consume(queue='order_queue', on_message_callback=callback)

# بدء الاستماع للرسائل
channel.start_consuming()

شفتوا السحر؟ لو شغلت المستهلك وبعدين شغلت المنتج 5 مرات، رح تلاحظ إنه الطلبات بتوصل للمستهلك واحد ورا الثاني، مع فاصل زمني، حتى لو المنتج أرسلهم كلهم في نفس اللحظة. ولو أوقفت المستهلك في نصف عمله، الرسالة اللي كان بيعالجها رح ترجع للطابور لما تشغله مرة ثانية!

نصائح من قلب المعركة ⚔️

بعد سنوات من التعامل مع هذه الأنظمة، تعلمت كم شغلة مهمة ما بتلاقيها في الكتب:

  • التكرارية الآمنة (Idempotency) هي مفتاح الأمان: شو بصير لو المستهلك عالج الطلب (مثلاً خصم الفلوس) بس “مات” قبل ما يبعث الـ `ack`؟ الطابور رح يرجعله نفس الرسالة مرة ثانية! لازم الكود تبعك يكون “Idempotent”، يعني لو تنفذ 10 مرات على نفس الطلب، النتيجة تكون نفس نتيجة تنفيذه مرة واحدة. مثلاً، قبل ما تسجل طلب جديد، تأكد من وجوده عن طريق رقم الطلب الفريد.
  • المراقبة مش رفاهية: لازم تراقب طول الطابور (Queue Length). لو الطابور عماله بيطول ومش بينقص، هذا مؤشر خطير إنه المستهلكين مش ملاحقين على الشغل. لازم يكون عندك تنبيهات (Alerts) على هاي الحالة.
  • استخدم طوابير الرسائل الميتة (Dead-Letter Queues): شو بصير لو في رسالة “خربانة” وكل مرة المستهلك بيحاول يعالجها بيفشل؟ رح تضل ترجع للطابور وتعمل حلقة لانهائية من الفشل. الحل هو إعداد “طابور الرسائل الميتة” (DLQ). بعد عدد معين من المحاولات الفاشلة، الرسالة بتنتقل تلقائياً للـ DLQ عشان المطورين يشوفوها ويحللوا المشكلة بدون ما توقف كل الشغل.
  • اختر الأداة المناسبة: RabbitMQ رائع، لكن مش هو الوحيد. عندك Kafka مناسب جداً لكميات البيانات الهائلة والـ Streaming، وعندك SQS من أمازون لو بتشتغل على AWS، وعندك Redis لو بدك حل أبسط وأسرع لمهام معينة. لا تتقيد بأداة واحدة، افهم مشكلتك أولاً ثم اختر الحل.

الخلاصة والزبدة 📝

طوابير الرسائل مش مجرد أداة تقنية، هي طريقة تفكير في تصميم الأنظمة. بتجبرك تبني أنظمة مرنة، صامدة، وقابلة للتوسع. هي اللي بتفصل بين نظام “بيمشي الحال” ونظام “جاهز للمعارك الكبرى”.

نصيحتي لكل مطور أو مهندس برمجيات: لا تنتظر الكارثة حتى تتعلم الدرس. ابدأ اليوم، حتى في مشاريعك الصغيرة، وفكر: “كيف ممكن أستخدم طابور رسائل هنا عشان أفصل بين المهام وأزيد الموثوقية؟”. القليل من التخطيط اليوم يوفر الكثير من ليالي القلق والـ “يا ريت” في المستقبل.

والله الموفق. 👍

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

التكنلوجيا المالية Fintech

كان المحتالون يرقصون بين قواعدنا: كيف أنقذتنا ‘نماذج اكتشاف الشذوذ’ من جحيم الاحتيال؟

في هذه المقالة، أشارككم قصة حقيقية من قلب المعركة ضد الاحتيال المالي. نستكشف كيف فشلت الأنظمة التقليدية وكيف كانت نماذج اكتشاف الشذوذ (Anomaly Detection) طوق...

24 مايو، 2026 قراءة المزيد
البنية التحتية وإدارة السيرفرات

كانت بنيتنا التحتية قصراً من ورق: كيف أنقذنا Terraform من جحيم “النقرات اليدوية” والكوارث الحتمية؟

أشارككم قصة حقيقية من قلب المعركة التقنية، كيف انتقلنا من فوضى إدارة السيرفرات اليدوية التي كادت أن تدمر مشروعنا، إلى عالم الهندسة المنظمة والموثوقة باستخدام...

24 مايو، 2026 قراءة المزيد
ادارة الفرق والتنمية البشرية

من الخوف إلى الإبداع: كيف أنقذت “السلامة النفسية” فريقي من شلل الصمت القاتل؟

أشارككم قصة حقيقية من مسيرتي كقائد فريق تقني، حيث كان الخوف من الخطأ يشلّ أعضاء الفريق ويقتل الإبداع. سأستعرض كيف يمكن لمفهوم "السلامة النفسية" أن...

24 مايو، 2026 قراءة المزيد
​معمارية البرمجيات

كانت واجهاتنا شبكة عنكبوت: كيف أنقذ نمط ‘بوابة الواجهة البرمجية’ (API Gateway) مشروعنا من الفوضى؟

واجهات المستخدم تتحدث مع عشرات الخدمات المصغرة؟ فوضى عارمة! في هذه المقالة، أسرد لكم حكايتي مع هذه المشكلة وكيف كان نمط 'بوابة الواجهة البرمجية' (API...

23 مايو، 2026 قراءة المزيد
ذكاء اصطناعي

كان بحثنا يفهم الكلمات لا المعاني: كيف أنقذتنا ‘التضمينات المتجهة’ (Vector Embeddings) من جحيم البحث الحرفي؟

بتذكر مرة كنا بنبني نظام بحث داخلي لشركة، وكان الموظف يسأل "كيف آخذ إجازة مرضية؟" والنظام ما يرجعله إشي، لأن المستند الرسمي عنوانه "سياسة الإجازات...

23 مايو، 2026 قراءة المزيد
البودكاست