مشروع: تصميم نظام خدمات مصغّرة
مشروع: تصميم نظام خدمات مصغّرة
كل مبدأ غطّيناه في هذا البرنامج التعليمي — السياقات المحدودة، وقاعدة بيانات لكل خدمة، والتواصل المتزامن وغير المتزامن، وتنسيق الـ Saga، والمخاوف المشتركة — يجب أن يتقاطع في نهاية المطاف في تصميم واحد متماسك. يشرح هذا الدرس بالتفصيل كيفية تحليل نطاق تجاري واقعي لبيئة تجارة إلكترونية وتقسيمه إلى خدمات ذات حدود محكمة، مع تبرير كل قرار بمستوى يحتاجه المطور في العمل الفعلي، ويُظهر كيف تتصل الخدمات الناتجة كمكوّنات Spring Boot 3 قابلة للتشغيل.
النطاق: سوق إلكتروني
يُدير النشاط التجاري سوقًا إلكترونيًا يضع فيه البائعون المنتجات للبيع، ويضع العملاء طلبات الشراء، ويُجري معالج المدفوعات عمليات الدفع ببطاقات الائتمان، ويتولى فريق التنفيذ شحن الطرود. تشمل القدرات الإضافية البحث والإشعارات وبوابة تقارير الإدارة. قبل كتابة فئة واحدة تحتاج إلى رسم خريطة النطاق باستخدام Event Storming — سرد كل حدث في النطاق بترتيب زمني، ثم تلوينها حسب قدرة الأعمال للكشف عن حدود الخدمات الطبيعية.
أبرز أحداث النطاق المُحدَّدة:
- ProductListedBySeller, ProductUpdated, ProductDeactivated
- CartItemAdded, CheckoutInitiated
- OrderPlaced, OrderConfirmed, OrderCancelled
- PaymentAuthorised, PaymentFailed, RefundIssued
- ShipmentCreated, PackageDispatched, DeliveryConfirmed
- CustomerRegistered, EmailVerified, PasswordChanged
يؤدي تجميع الأحداث حسب الفريق المسؤول عنها — لا حسب التشابه التقني — إلى السياقات المحدودة التالية:
التحليل إلى خدمات
تظهر ست خدمات من خريطة الأحداث. كل منها تمتلك قاعدة بياناتها الخاصة، وتُعرّض واجهة REST API للقراءات المتزامنة، وتنشر وتستهلك الأحداث عبر Kafka لعمليات تغيير الحالة.
- Catalog Service — عمليات CRUD للمنتجات؛ فهرس Elasticsearch للبحث. ينشر
ProductUpdated. - Order Service — عربة التسوق ودورة حياة الطلب. ينشر
OrderPlacedوOrderCancelled؛ يستمع إلىPaymentAuthorisedوShipmentCreated. - Payment Service — تكامل بوابة الدفع. ينشر
PaymentAuthorisedوPaymentFailed. - Inventory Service — حجز المخزون. يستمع إلى
OrderPlaced؛ ينشرStockReservedوStockInsufficient. - Fulfilment Service — ملصقات الشحن والتكامل مع شركات الناقل. يستمع إلى
PaymentAuthorised؛ ينشرPackageDispatched. - Identity Service — حسابات المستخدمين وإصدار JWT وإدارة كلمات المرور. تتحقق جميع الخدمات الأخرى من الرموز الصادرة عنه.
Order Service — الهيكل الأساسي
تُوضّح خدمة الطلبات بنية Spring Boot 3 النموذجية. تُعرّض واجهة REST API لسير عملية الدفع وتنشر أحداث النطاق إلى Kafka للخدمات المنبثقة.
@TransactionalEventListener(phase = AFTER_COMMIT) الخاص بـ Spring لضمان نشر الحدث مرة واحدة بالضبط نسبةً إلى الكتابة في قاعدة بياناتك.
عقود أحداث Kafka
مخططات الأحداث هي واجهتك البرمجية العامة. استخدم Avro مع Schema Registry حتى تُكتشف التغييرات غير المتوافقة في وقت البناء لا في وقت التشغيل على الإنتاج. مخطط Avro أدنى حد لـ OrderPlaced:
تستمع خدمة المخزون إلى الموضوع ذاته. مُستهلكها مُتسامح مع التكرار (idempotent) — إذا وصلت رسالة OrderPlaced ذاتها مرتين (Kafka تضمن التسليم مرة على الأقل)، تجد المحاولة الثانية الحجز قائمًا بالفعل وتُهمله:
Saga الدفع عند الخروج
إتمام الطلب هو Saga متعددة الخدمات: Order → Inventory → Payment → Fulfilment. استخدم Saga قائمة على التنسيق الكوريوغرافي لهذا السير — لا منسّق مركزي، كل خدمة تتفاعل مع الأحداث وتنشر أحداث التعويض عند الفشل:
- Order Service ينشر
OrderPlaced. - Inventory Service يحجز المخزون → ينشر
StockReservedأوStockInsufficient. - Payment Service يُجري الدفع → ينشر
PaymentAuthorisedأوPaymentFailed. - عند أي فشل، تُلغي أحداث التعويض الخطوات السابقة (
StockReleased،OrderCancelled). - عند النجاح الكامل، تنشئ Fulfilment Service شحنةً.
الأمان بين الخدمات: تمرير JWT
تُصدر Identity Service رمز JWT موقّعًا عند تسجيل الدخول. تتحقق كل خدمة أخرى من الرمز محليًا باستخدام المفتاح العام لـ Identity Service — لا رحلة ذهاب وإياب مع كل طلب. يُبسّط Spring Security 6 هذا إلى خاصية واحدة:
ClientCredentials (من آلة إلى آلة) حتى تتمكن Inventory Service من التدقيق في هوية المُستدعي.
Spring Cloud Gateway — نقطة الدخول الوحيدة
اعرض اسم مضيف عام واحد فقط. يوجّه Spring Cloud Gateway الطلبات إلى الخدمة الصحيحة، ويُنفّذ المصادقة عند الحافة، ويُزيل الترويسات الداخلية التي لا ينبغي للعملاء رؤيتها:
ربط المراقبة
في النظام الموزّع يتفرّع طلب المستخدم الواحد عبر خدمات متعددة. بدون تتبع مترابط لا تستطيع إعادة بناء ما حدث. أضف Micrometer Tracing مع Zipkin إلى كل خدمة — يُهيّئه Spring Boot 3 تلقائيًا من تبعيّتين:
تتضمّن كل سطر في السجل تلقائيًا traceId وspanId. اجمع السجلات في مخزن مركزي (ELK أو Loki) وصفّ حسب traceId لمتابعة طلب الدفع عبر Order وInventory وPayment وFulfilment في استعلام واحد.
ملخّص قرارات التصميم
- ست خدمات متوافقة مع قدرات الأعمال لا مع الطبقات التقنية.
- قاعدة بيانات لكل خدمة: PostgreSQL لـ Order/Payment/Fulfilment، وMongoDB لـ Catalog، وRedis لـ Inventory (فحوصات الحجز السريعة)، وMySQL لـ Identity.
- غير متزامن بشكل افتراضي: العمليات التي تُغيّر الحالة تمرّ عبر Kafka؛ يُحجز REST المتزامن للاستعلامات التي تحتاج ردًّا فوريًا.
- Saga كوريوغرافي لسير الدفع؛ يكون Saga تنسيقي أفضل إذا تجاوزت الخطوات ستّة أو أصبحت منطق التعويض معقدًا.
- JWT عند الحافة وبين الخدمات — لا حالة جلسة في أي مكان.
- بوابة واحدة — لا يعرف العملاء قط تضاريس الخدمات؛ عناوين URL الداخلية معتمة.
مع هذه البنية في مكانها يمكن إعادة نشر أي خدمة منفردة أو تحجيمها أفقيًا أو استبدالها كليًّا دون المساس بالخدمات الأخرى — وهو الوعد المحدّد لأسلوب الخدمات المصغّرة.