الأنماط والأنماط المضادة
الأنماط والأنماط المضادة
نضجت معمارية الخدمات المصغّرة بما يكفي لتتبلور من التجارب المشتركة لآلاف الأنظمة الإنتاجية مفردات واضحة من الأنماط — الحلول المُجرَّبة للمشكلات المتكررة — والأنماط المضادة — المقاربات التي تبدو معقولة لكنها تُلحق ضررًا بالغًا على نطاق واسع. إنّ معرفة هذه المفردات تُمكّنك من تمييز المشكلة مبكرًا وتسميتها بدقة وتطبيق العلاج الصحيح.
نمط الشجرة الخانقة (Strangler Fig)
عند ترحيل تطبيق متجانس (Monolith) قديم إلى خدمات مصغّرة، نادرًا ما تملك رفاهية إيقاف كل شيء وإعادة الكتابة من الصفر. يتيح نمط الشجرة الخانقة (المُسمّى على اسم الشجرة التي تنمو حول مضيفها) استخراج الوظائف بصورة تدريجية. طبقة توجيه أمام التطبيق القديم تُعيد توجيه مسارات محددة إلى خدمات مصغّرة جديدة كلما أصبحت جاهزة؛ يتقلص التطبيق القديم مع الوقت حتى يُوقف تشغيله كليًا.
في Spring Cloud Gateway، يُعبَّر عن طبقة التوجيه ببساطة في YAML:
تستطيع كل فريق استخراج سياق محدود واحد في كل مرة دون الحاجة إلى تحويل محفوف بمخاطر كبيرة. الأمان لا يتراجع أيضًا: يُطبّق البوابة المصادقةَ قبل التوجيه، فيتمتع التطبيق القديم والخدمة الجديدة بنفس التحقق من الرمز المميز.
نمط السيارة الجانبية (Sidecar)
لا ينبغي أن تسكن الاهتمامات المتقاطعة كـ mTLS والتتبع الموزع وإعادة المحاولات في كود تطبيق كل خدمة. ينشر الـ Sidecar حاوية مساعدة بجانب كل مثيل خدمة — في نفس الـ Pod في Kubernetes — تتولى بشفافية تلك الاهتمامات عبر اعتراض حركة الشبكة.
نمط قاطع الدائرة (Circuit Breaker)
لقد ناقشنا قاطعات الدائرة في سياق المرونة، لكنها أيضًا نمط معماري يستحق التسمية الصريحة هنا. يجب على الخدمة التي تستدعي تبعية خارجية أن تُغلّف تلك الاستدعاء في قاطع دائرة: آلة حالات تتتبع معدلات الفشل، وعند تجاوز عتبة الفشل تفتح الدائرة فتفشل الاستدعاءات اللاحقة بسرعة دون أن تصل إلى التبعية أصلًا.
مع Resilience4j في Spring Boot 3:
نمط Saga (كنمط معماري)
المعاملات الموزعة عبر الخدمات المصغّرة مستحيلة بإيداع ACID واحد. يُفكّك نمط Saga المعاملةَ التجارية الطويلة إلى سلسلة من المعاملات المحلية، يُصدر كل منها حدثًا أو أمرًا يُشغّل الخطوة التالية. إذا فشلت أي خطوة، تُعيد معاملات التعويض العمل السابق.
طبقة مكافحة التلوث (Anti-Corruption Layer)
عند التكامل مع نظام قديم أو خدمة طرف ثالث تستخدم نموذج مجال مختلفًا، لا تدع ذلك النموذج الخارجي يتسرب إلى سياقك المحدود. أدخل طبقة مكافحة التلوث (ACL) — حد ترجمة يُحوّل البيانات الواردة إلى نموذجك الخاص والبيانات الصادرة إلى نموذجهم.
تضمن ACL أن التغيير في نموذج النظام القديم يستلزم تعديلًا في المترجم فقط، لا في كامل خدمتك.
نمط التوحيد الموزع المضاد (Distributed Monolith)
التوحيد الموزع هو أخطر نمط مضاد في الخدمات المصغّرة. يبدو كنشر خدمات مصغّرة — خدمات متعددة، مستودعات منفصلة، نشر مستقل — لكنه يتصرف كتوحيد لأن الخدمات مترابطة ارتباطًا وثيقًا في وقت التشغيل.
أعراض التوحيد الموزع:
- قاعدة بيانات مشتركة: تقرأ خدمات متعددة وتكتب في نفس الجداول. يتطلب تغيير المخطط تنسيق فرق متعددة.
- سلاسل متزامنة: الخدمة A تستدعي B التي تستدعي C التي تستدعي D في طلب واحد. أي عقدة تتوقف تُسقط السلسلة بأكملها.
- واجهات ثرثارة: عشرة استدعاءات REST دقيقة للبيانات التي يمكن تجميعها في خدمة واحدة، مما يُضيف زمن استجابة وسطح فشل على كل طلب.
- كائنات مجال مشتركة: مكتبة
dtoأوmodelمشتركة تستوردها كل خدمة. تغيير حقل يستلزم إصدار جميع المستهلكين ونشرهم في آنٍ واحد.
common-models يحمل كائنات المجال عبر حدود الخدمات هو أكثر الطرق شيوعًا لتحويل مشروع الخدمات المصغّرة خفيةً إلى توحيد موزع. اقبل بعض التكرار — DTO باسم UserSummary في كل خدمة — بدلًا من مشاركة كيان User عبر حدود الشبكة.
السبب الجذري للتوحيد الموزع يكمن دائمًا تقريبًا في تصميم حدود خدمات غير صحيحة — قُسِّمت الخدمات على طبقات تقنية (خدمة واجهة المستخدم، خدمة منطق الأعمال، خدمة البيانات) بدلًا من قدرات المجال (إدارة الطلبات، الشحن، الفوترة). راجع الدرس الثالث حول السياقات المحدودة كلما وجدت نفسك تصارع الاقتران المتزامن.
نمط واجهة API الثرثارة المضاد (Chatty API)
لاستدعاء خدمة عن بُعد حد أدنى من زمن الاستجابة لا تمتلكه الاستدعاءات داخل العملية. واجهة برمجية تتطلب من العميل عشرة استدعاءات لتجميع صفحة واحدة تُضاعف ذلك الحد عشر مرات. والعلاج هو أحد الخيارات التالية:
- تجميع خشن الحبيبات: أضف نقطة نهاية تُعيد كل البيانات التي يحتاجها المستهلك في استدعاء واحد.
- GraphQL أو BFF (خلفية للواجهة الأمامية): خدمة BFF مخصصة (في الغالب واحدة لكل نوع عميل — ويب، موبايل) تجمّع البيانات من خدمات متعددة من جانب الخادم وتُعيدها في حمولة واحدة، مما يُلغي التشعيع من جانب العميل.
- إسقاط حدث المجال: اعرض البيانات التي يحتاجها المستهلك في نموذج قراءة خاص به (جانب القراءة في CQRS) حتى يتمكن من الرد على الاستعلامات محليًا.
تحديد تفكيك خدمتك بنفسك
تجربة إبهام عملية: إذا كانت خدمتان تُنشران دائمًا معًا فهما على الأرجح خدمة واحدة. وبالمثل، إذا كان تغيير إحداهما يُجبر دائمًا على تغيير الأخرى، فإنهما تتشاركان مفهومًا تجاريًا ينتمي إلى سياق محدود واحد. استخدم هذا المنظار خلال مراجعات الكود وفحوصات ملاءمة المعمارية لاكتشاف انجراف الاقتران قبل أن يتراكم في توحيد موزع.
الخلاصة
الأنماط التي تناولناها هنا — الشجرة الخانقة، الـ Sidecar، قاطع الدائرة، Saga، وطبقة مكافحة التلوث — يحل كل منها فئة محددة من المشكلات. التوحيد الموزع وواجهة API الثرثارة هما نمطا الفشل اللذان تصطدم بهما معظم الفرق أولًا. يجمع الدرس الأخير من هذه الدورة التعليمية كل هذه الأفكار في تمرين تصميم عملي.