العمارة المُدفوعة بالأحداث وصعود طوابير الرسائل

مقدمة

يتعلم معظم المهندسين الأنظمة الموزعة من منظور التواصل بنموذج الطلب-الاستجابة: يستدعي عميل خدمة، ويحظر بانتظار الرد، ويستلم استجابة متزامنة. هذا النموذج بديهي لأنه يحاكي استدعاء دالة، ويعمل جيدًا عندما يحتاج المُستدعي فعليًا لإجابة فورية ويستطيع المُستدعَى تقديمها بشكل موثوق ضمن نافذة زمنية مقبولة. لكن حصة كبيرة ومتنامية من تفاعلات الأنظمة الواقعية لا تتناسب فعليًا مع هذا الشكل. عند وضع طلب، تحتاج عشرات الأنظمة اللاحقة - المخزون، الشحن، التحليلات، كشف الاحتيال، إشعارات البريد الإلكتروني - لمعرفة ذلك، لكن لا واحد منها يحتاج لحظر تدفق إتمام الشراء بانتظار دوره.

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

الطوابير مقابل التدفقات: نموذجان متمايزان

غالبًا ما تُناقش طوابير الرسائل وتدفقات الأحداث بالتبادل، لكنها تمثّل نماذج توصيل متمايزة حقًا بضمانات مختلفة. طابور الرسائل التقليدي، الذي تُجسّده RabbitMQ أو Amazon SQS، مبني حول فكرة أن الرسالة تُستهلك مرة واحدة ثم تُزال: يسحب عامل رسالة من الطابور، يعالجها، ويؤكدها، وعندها تختفي. يتطابق هذا النموذج بشكل طبيعي مع أحمال عمل توزيع المهام - مجموعة من العمال يعالجون قائمة أعمال متراكمة مشتركة - حيث يجب أن يتعامل عامل واحد بالضبط مع كل وحدة عمل.

تتخذ منصات بث الأحداث، التي يُجسّدها Apache Kafka، نهجًا مختلفًا جوهريًا: تُضاف الأحداث لسجل دائم ومرتب ويُحتفَظ بها لفترة قابلة للتهيئة - غالبًا أيامًا أو أسابيع، وأحيانًا إلى أجل غير مسمى - بدلاً من حذفها عند الاستهلاك. يستطيع مستهلكون مستقلون عديدون قراءة نفس تدفق الأحداث كل بوتيرته الخاصة، ويستطيع مستهلك جديد أُضيف بعد شهور، إذا سمحت سياسة الاحتفاظ بذلك، إعادة تشغيل تاريخ الأحداث بأكمله من البداية. قدرة إعادة التشغيل هذه هي ما يجعل تدفقات الأحداث قيّمة ليس فقط لتوزيع المهام بل كمصدر حقيقي للحقيقة حول ما حدث عبر نظام بمرور الوقت، خاصية لا تشاركها الطوابير إذ أن الرسالة المُستهلَكة تختفي ببساطة.

ضمانات التوصيل ومتطلب المُطابقة

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

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

مفاضلة التنسيق مقابل التنظيم

تُدخل العمارة المُدفوعة بالأحداث تشعبًا تصميميًا حقيقيًا لتنسيق عمليات أعمال متعددة الخطوات: التنسيق التلقائي، حيث يتفاعل كل خدمة بشكل مستقل مع الأحداث ولا يمتلك أي مكوّن واحد رؤية للعملية الكاملة، مقابل التنظيم، حيث توجّه خدمة تنسيق مخصصة صراحة كل خطوة من سير العمل. يتوسع التنسيق التلقائي جيدًا تنظيميًا، إذ تستطيع الفرق إضافة مستهلكي أحداث جدد دون لمس أو حتى معرفة الموجودين، لكنه يجعل عملية الأعمال الكاملة صعبة الملاحظة والتفكير فيها ككل.

يحافظ التنظيم، المُنفَّذ عبر أنماط مثل نمط Saga أو محركات سير عمل مثل Temporal أو AWS Step Functions، على العملية من البداية للنهاية صريحة وقابلة للملاحظة مركزيًا، بتكلفة إدخال مكوّن تنسيق يصبح تبعية لكل خطوة ويتطلب تصميمًا دقيقًا لمعالجة الإخفاقات الجزئية بسلاسة. تنتهي معظم الأنظمة واسعة النطاق باستخدام مزيج من كلا النمطين، مختارة التنسيق التلقائي للمخاوف ضعيفة الترابط والمتطورة بشكل مستقل، والتنظيم للعمليات حيث تهم صحة وقابلية ملاحظة التدفق الكامل فعليًا أكثر من الاستقلالية على مستوى الفريق.

تطور المخطط ومشكلة العقد

لأن الأنظمة المُدفوعة بالأحداث تفصل المنتجين عن المستهلكين، يصبح الحدث نفسه عقدًا ضمنيًا بين فرق قد لا تنسق نشراتها مباشرة أبدًا، ويصبح تطوير ذلك العقد دون كسر المستهلكين الموجودين انضباطًا هندسيًا حقيقيًا بدلاً من فكرة لاحقة. منتج يعيد تسمية حقل أو يغيّر نوعه دون تحذير يمكن أن يكسر بصمت كل مستهلك لاحق، نمط فشل خبيث بشكل خاص لأن اختبارات المنتج نفسه ستنجح - يظهر الخطأ فقط في نظام مستهلك، ربما يملكه فريق مختلف تمامًا، بعد أيام.

تعالج سجلات المخططات، مثل تلك المُضمَّنة في توزيعة Confluent لـKafka، هذا بفرض قواعد توافق - خلفي، أمامي، أو كامل - عند نقطة تسجيل إصدار مخطط جديد، رافضة محاولة منتج نشر تغيير مخطط قد يكسر المستهلكين الموجودين قبل أن يصل ذلك التغيير للإنتاج أصلاً. مقترنة باتفاقية صارمة بإضافة حقول اختيارية فقط وعدم إعادة استخدام أو إزالة الحقول الموجودة أبدًا، تُحوّل سجلات المخططات ما قد يكون عقدًا اجتماعيًا ضمنيًا وسهل الانتهاك بين الفرق إلى عقد مفروض ومُتحقَّق منه آليًا.

دراسة حالة: LinkedIn وأصول Kafka

قصة أصل Apache Kafka نفسها في LinkedIn مفيدة حول نطاق المشكلة التي بُني بث الأحداث لحلها. قبل Kafka، كانت LinkedIn قد تراكمت لديها شبكة من خطوط أنابيب بيانات نقطة إلى نقطة تربط أنظمة داخلية مختلفة - كل نظام جديد يحتاج بيانات من نظام قائم يتطلب تكاملاً مخصصًا جديدًا، مُنتجة انفجارًا توافيقيًا من الاتصالات الهشة والمُصانة فرديًا التي أصبحت أصعب فأصعب في التفكير فيها أو توسيعها مع نمو الشركة. كانت رؤية Kafka الأساسية استبدال شبكة التكاملات نقطة إلى نقطة هذه بسجل مركزي دائم واحد يستطيع أي نظام النشر إليه أو الاشتراك منه.

النمط الذي رادت LinkedIn - معاملة تدفق أحداث أعمال الشركة كسجل دائم وقابل لإعادة التشغيل ومتاح مركزيًا بدلاً من مجموعة رسائل نقطة إلى نقطة عابرة - أصبح منذ ذلك الحين العمارة الافتراضية لأي مؤسسة تعمل على نطاق تحتاج فيه عشرات الأنظمة الداخلية للتفاعل مع نفس أحداث الأعمال الأساسية.

الضغط الخلفي وتأخر المستهلك

تحدٍ تشغيلي بحت تُدخله الأنظمة المُدفوعة بالأحداث هو تأخر المستهلك: الفجوة بين معدل إنتاج الأحداث ومعدل قدرة مستهلك معين على معالجتها. لأن المنتجين والمستهلكين منفصلون، يستطيع منتج مواصلة النشر بأقصى سرعة حتى بينما يتأخر مستهلك لاحق أكثر فأكثر، سيناريو غير مرئي للمنتج تمامًا لكن يمكن أن يتراكم بصمت لمشكلة خطيرة - بيانات قديمة تصل لأنظمة لاحقة بتأخير ساعات أو أيام.

مراقبة تأخر المستهلك كمقياس تشغيلي من الدرجة الأولى، إلى جانب إشارات أكثر تقليدية مثل معدل الخطأ والكمون، ضرورية لالتقاط هذه الفئة من المشكلة قبل أن تصبح حادة، وتُنفذ الأنظمة المُدفوعة بالأحداث الناضجة عادة آليات ضغط خلفي - إبطاء أو إيقاف منتج بتعمد، أو توسيع قدرة المستهلك ديناميكيًا استجابة لتأخر متنامٍ - بدلاً من افتراض أن أسطول مستهلكين ثابت الحجم سيواكب دائمًا معدلات إنتاج متغيرة.

الخاتمة

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

أرسل رسالة

×
اضغط على فريق المساعدة في الاسفل لكي يتم نقلك لتطبيق الواتساب