في المشهد الحديث لأنظمة الموزعة، لم تعد القدرة على فصل المكونات مجرد رفاهية، بل أصبحت ضرورة. ومع نمو التطبيقات من الهياكل الأحادية إلى خدمات مصغرة معقدة، تبرز الحاجة إلى اتصال موثوق وقابل للتوسع وغير متزامن. هنا يأتي دور أنظمة المراسلة والهندسة المعمارية المعتمدة على الأحداث (EDA). ومن خلال الاستفادة من طوابير الرسائل، وأنماط النشر/الاشتراك، ومصادر الأحداث، يمكن للمطورين بناء أنظمة مرنة، متاحة للغاية، وسهلة التوسع.
الأساسيات: الاتصال غير المتزامن ونمط النشر/الاشتراك
في جوهرها، تعتمد الهندسة المعمارية المعتمدة على الأحداث على المبدأ القائل إن الخدمات لا ينبغي أن تنتظر الاستجابات، بل يجب أن تتفاعل مع الأحداث. ويتم تحقيق ذلك من خلال الاتصال غير المتزامن، والذي يتم تنفيذه غالباً عبر طوابير الرسائل أو خدمات الوسطاء. النمط الأكثر شيوعاً هو النشر/الاشتراك (Pub/Sub)، حيث ينشر المنتجون الرسائل في موضوع أو طابور، ويشترك المستهلكون لاستلامها. يضمن هذا الفصل أن المنتج لا يحتاج إلى معرفة هوية المستهلك، ولا يحتاج المستهلك إلى أن يكون متصلاً بالتحديد في اللحظة التي يحدث فيها الحدث.
لنأخذ في الاعتبار منصة تجارة إلكترونية قياسية. عندما يضع المستخدم طلباً، يجب على النظام تحديث المخزون، ومعالجة الدفع، وإرسال بريد إلكتروني للتأكيد، وتسجيل المعاملة. في النموذج المتزامن، إذا كان خدمة البريد الإلكتروني معطلة، قد يفشل الطلب. أما في النموذج غير المتزامن، فإن خدمة الطلبات تنشر حدثاً OrderPlaced وتنتقل إلى المهام التالية. تقوم خدمات منفصلة باستهلاك هذا الحدث للتعامل مع مهامها المستقلة بشكل منفصل.
اختيار الوسيط المناسب: Kafka مقابل RabbitMQ مقابل Pulsar
يعد اختيار وسيط الرسائل المناسب أمراً بالغ الأهمية. وبينما يتعامل اللاعبون الكبار الثلاثة—Apache Kafka وRabbitMQ وApache Pulsar—مع وساطة الرسائل، فإن هندساتها الأساسية وحالات الاستخدام تختلف بشكل كبير.
Apache Kafka: منصة تدفق الأحداث
تم تصميم Kafka لتدفق الأحداث عالي الإنتاجية والمقاوم للأعطال. فهو يستخدم نموذج سجل الالتزام الموزع، مما يجعله مثالياً للسيناريوهات التي تتطلب إمكانية إعادة التشغيل واستهلاك البيانات على نطاق واسع. غالباً ما يكون Kafka الخيار الأول للتحليلات في الوقت الفعلي، وتجميع السجلات، ومصادر الأحداث.
إليك كيفية إنتاج رسالة في Kafka باستخدام عميل Python مفاهيمي:
from kafka import KafkaProducer
import json
producer = KafkaProducer(
bootstrap_servers='localhost:9092',
value_serializer=lambda v: json.dumps(v).encode('utf-8')
)
message = {"event": "order_placed", "orderId": "12345"}
producer.send('orders-topic', value=message)
producer.flush()
RabbitMQ: وسيط الرسائل المرن
يتفوق RabbitMQ في سيناريوهات التوجيه المعقدة. وعلى عكس سجل Kafka الخطي، يستخدم RabbitMQ طوابير مع مبادلات (exchanges) تقوم بتوجيه الرسائل بناءً على قواعد محددة (مباشرة، موضوع، رؤوس). إنه ممتاز لطوابير المهام، وأنماط RPC، والتطبيقات التي تتطلب توجيه رسائل معقداً وأولويات. ومع ذلك، فهو أقل ملاءمة لتدفق البيانات الضخمة مقارنة بـ Kafka.
Apache Pulsar: الموحّد الأصلي للسحابة
يحاول Apache Pulsar سد الفجوة بين التدفق والرسائل. فهو يوفر قابلية التوسع والمتانة التي يوفرها التخزين البنيوي للسجلات في Kafka، مع مرونة وميزات تعدد المستأجرين في RabbitMQ. يفصل Pulsar بين الحوسبة والتخزين، مما يتيح النسخ المتماثل عبر العناقيد المتعددة والتكامل مع الحوسبة الخالية من الخوادم (Serverless)، مما يجعله منافساً قوياً للهندسات المعمارية الأصلية للسحابة.
تنفيذ مصادر الأحداث
تأخذ مصادر الأحداث مفهوم المعتمد على الأحداث إلى أبعد من ذلك من خلال استخدام الأحداث كمصدر رئيسي للحقيقة. بدلاً من تخزين الحالة الحالية للكيان فقط (على سبيل المثال، "الرصيد: 100 دولار")، تقوم بتخزين كل تغيير في الحالة (على سبيل المثال، "إيداع 50 دولاراً"، "سحب 20 دولاراً"، "إيداع 70 دولاراً"). يوفر هذا النهج سجلاً تدقيقياً غير قابل للتغيير ويسمح لك بإعادة بناء حالة أي كيان في أي نقطة زمنية.
الخاتمة
يتطلب اعتماد الهندسة المعمارية المعتمدة على الأحداث مراعاة دقيقة لمتطلبات الإنتاجية وزمن الاستجابة وتوجيه النظام الخاص بك. سواء اخترت Kafka للتدفق، أو RabbitMQ للتوجيه المعقد، أو Pulsar لنهج موحد أصلي للسحابة، يظل الهدف واحداً: بناء أنظمة مفصولة، مرنة، وجاهزة للتوسع. ومن خلال إتقان هذه الأدوات، تمكّن فريق التطوير الخاص بك من إنشاء برمجيات يمكنها التكيف مع احتياجات الأعمال المتغيرة بمرونة وأناقة.