مشروع: اختيار المعمارية المناسبة
مشروع: اختيار المعمارية المناسبة
على مدار هذا البرنامج التعليمي، درست تسعة أنماط معمارية متميزة — من المعمارية الأحادية الكلاسيكية، مرورًا ببوابات API وشبكات الخدمات، وCQRS والمصادر المبنية على الأحداث، وصولًا إلى الوظائف بلا خوادم. التحدي الختامي هو تطبيق هذه المعرفة كما يفعل الممارس المحترف: انطلاقًا من موجز نظام واقعي، تختار التوليفة الصحيحة من الأنماط، وتبرر كل خيار بمقايضات حقيقية، وتُنتج تصميمًا يمكنك الدفاع عنه.
يأخذك هذا الدرس في مثال عملي — منتج خيالي لكنه واقعي — حتى ترى عملية صنع القرار من البداية حتى النهاية. استخدمه قالبًا لمقترحاتك المعمارية الخاصة.
موجز النظام
طُلب منك تصميم الجزء الخلفي لمنصة FleetTrack، وهي منصة لوجستية بالمتطلبات التالية:
- تتبع GPS في الوقت الفعلي — 50,000 مركبة كل منها ترسل موقعها كل 10 ثوانٍ (نحو 5,000 كتابة موقع/الثانية في الذروة).
- تطبيق الجوال للسائق — واجهة REST API لمهام العمل، والمستندات، وتعليمات الملاحة.
- لوحة تحكم الويب للمرسَل — خريطة حية بمواقع المركبات، وتحسين المسارات، والتنبيهات.
- التحليلات وإعداد التقارير — إعادة تشغيل المسارات التاريخية، وتقارير استهلاك الوقود، ولوحات SLA. الاستعلامات قد تمتد على بيانات شهور.
- محرك الإشعارات — إشعارات فورية ورسائل نصية لأحداث السياج الجغرافي (دخول مركبة منطقة أو خروجها).
- حجم الفريق: 12 مهندسًا حاليًّا، ينمو إلى نحو 35 على مدى عامين.
- النضج التشغيلي: البنية التحتية الأساسية على AWS، لكن الخبرة بـKubernetes محدودة.
الخطوة 1 — تحديد حدود النطاق
يسأل التصميم المبني على النطاق: أين تتغير اللغة الموحدة؟ في FleetTrack الحدود واضحة:
- نطاق الاستيعاب — يستقبل إطارات GPS الخام من المركبات.
- نطاق التتبع — يحتفظ بالحالة الراهنة للمركبة (الموقع، السرعة، الاتجاه).
- نطاق التوزيع — يدير المهام والسائقين والتكليفات.
- نطاق التحليلات — الاستعلامات التاريخية والتقارير المجمَّعة.
- نطاق الإشعارات — تقييم السياج الجغرافي وإرسال الرسائل.
تتناظر هذه الحدود بشكل طبيعي مع الخدمات. لكن مع 12 مهندسًا لا تريد 10 خدمات مستقلة من اليوم الأول. الخطوة الصحيحة هي مونوليث معياري لنطاق التوزيع والإشعارات (يتشاركان بيانات علائقية ويتغيران معًا)، وخدمات مستقلة فقط حيث يختلف نمط الحمل اختلافًا حقيقيًّا.
الخطوة 2 — تطبيق CQRS حيث تتباين القراءة والكتابة
مسار استيعاب GPS يكتب بمعدل 5,000 حدث/الثانية. لوحة المرسَل تقرأ الموقع الراهن لآلاف المركبات في آنٍ واحد. هاتان الحاجتان متناقضتان تمامًا: الجانب الكتابي يحتاج إنتاجية إلحاق عالية؛ الجانب القرائي يحتاج بحثًا نقطيًّا بأقل من 100 مللي ثانية.
هذا نموذج مثالي لـCQRS. الجانب الأمري يُلحق إطارات GPS الخام بسجل أحداث (موضوع Kafka أو Kinesis). يقرأ مستهلك الإسقاط ذلك التيار ويُحدِّث جدول current_positions في Redis، مع إبقاء أحدث حالة لكل مركبة مُفهرسةً برقمها. الجانب الاستعلامي يقرأ Redis فقط — لا يلمس سجل الأحداث الخام أبدًا أثناء الاستعلام.
يستهلك نطاق التحليلات نفس موضوع Kafka بشكل غير متزامن عبر مستهلك ثانٍ يكتب إلى مخزن عمودي (Amazon Redshift أو ClickHouse) للمسح بعيد المدى. مسار الكتابة لا يتأثر بالاستعلامات التحليلية البطيئة.
الخطوة 3 — اختيار نمط API لطبقة العملاء
تطبيق الجوال للسائق ولوحة تحكم الويب للمرسَل لديهما احتياجات بيانات مختلفة تمامًا. يريد تطبيق الجوال نقطة نهاية /me/job واحدة تُعيد المهمة، والمركبة المكلَّفة، والملف الشخصي المُدمج في استدعاء واحد. اللوحة تريد تيارًا من التحديثات الفورية للمواقع لآلاف المركبات في آنٍ واحد.
هذه بالضبط المشكلة التي صُمِّم Backends for Frontends (BFF) لحلها. خدمتان BFF خفيفتان تجلسان خلف بوابة API:
- Mobile BFF — يجمع بيانات المهمة والسائق والمركبة في حزم مُحسَّنة للأجهزة المحمولة. يتعامل مع متطلبات المزامنة دون اتصال. GraphQL أو REST.
- Dashboard BFF — يحتفظ باتصال WebSocket لكل مرسَل؛ يدفع تحديثات مواقع Redis كـServer-Sent Events. يدير اشتراكات السياج الجغرافي لكل مستخدم.
الخطوة 4 — تحديد حدود المونوليث مقابل الخدمة
مع فريق من 12 مهندسًا وخبرة محدودة بـKubernetes، يُعدّ نشر كل نطاق كخدمة مستقلة مجازفة. التوصية لـFleetTrack عند الإطلاق:
- خدمات مستقلة (مبرَّرة بتباين الحمل): خدمة الاستيعاب، خدمة السياج الجغرافي، كلا BFFين.
- مونوليث معياري (وحدة نشر واحدة، وحدات داخلية مفصولة بوضوح): وحدة التوزيع + وحدة ملفات السائقين الشخصية + إدارة قوالب الإشعارات.
- بنية تحتية مُدارة: Kafka (MSK)، Redis (ElastiCache)، ClickHouse (أو Redshift). غير مستضافة ذاتيًّا.
مع نمو الفريق إلى 35 مهندسًا، تصبح وحدة التوزيع مرشحة للاستخراج — فريقها سيكون قد نما بما يكفي وحدودها النطاقية واضحة بالفعل داخل المونوليث، مما يجعل استخراج Strangler Fig مستقبلًا منخفض المخاطر.
الخطوة 5 — المصدر المبني على الأحداث لسجل التدقيق
بيانات GPS تعتمد على الأحداث بطبيعتها: كل نبضة موقع حقيقة غير قابلة للتغيير حدثت في لحظة محددة. تخزينها بهذه الطريقة (في Kafka مع نافذة استبقاء طويلة، أو في بحيرة Parquet غير قابلة للتغيير على S3) يمنحك مجانًا إعادة تشغيل المسارات، وفض النزاعات، والامتثال التنظيمي. لا تُعيد بناء الحالة عبر تعديل الصفوف — بل تُعيد تشغيل سجل الأحداث من أي طابع زمني.
وحدة التوزيع لا تحتاج إلى مصدر أحداث كامل. تكليفات المهام تتغير نادرًا والفريق لا يحتاج بعد إلى سجل تدقيق كامل هناك. الإفراط في تطبيق المصدر المبني على الأحداث يضيف عبئًا تشغيليًّا دون فائدة تناسبية. طبِّقه حيث يكون لثبات التاريخ قيمة عملية واضحة.
الخطوة 6 — أين تُفيد الخدمات اللاخادمية
عدة أحمال عمل في FleetTrack هي مرشحات ممتازة للخدمات اللاخادمية لأنها مفاجئة، قصيرة العمر، ونادرة:
- توليد التقارير — يطلب مرسَل ملخص الوقود لـ200 مركبة على مدى 90 يومًا. هذا مسح ثقيل يُنفَّذ بصفة متقطعة. دالة Lambda أو Cloud Run مُشغَّلة من قائمة انتظار تنطلق وتستعلم ClickHouse وتُنشئ PDF ثم تُغلَق. لا حاجة لخادم دائم لهذا الحمل النادر.
- استيراد مناطق السياج الجغرافي — يُرفع ملف GeoJSON بـ500 منطقة. دالة لاخادمية تُوزِّع المناطق وتُدرجها. تُنفَّذ مرة واحدة لكل رفع، مدفوعة بالأحداث بالكامل.
- صادرات الامتثال المجدولة — Lambda ليلي يُصدِّر بيانات ساعات القيادة إلى خادم SFTP تنظيمي.
المعمارية النهائية دفعةً واحدة
ملخص التبريرات
كل نمط مختار له سبب محدد وقابل للقياس:
- بوابة API — نقطة إنهاء TLS واحدة، تحد معدل GPS من 50,000 جهاز، وتتولى المصادقة مركزيًّا.
- BFF (جوال + لوحة تحكم) — تطبيق السائق يحتاج REST مُجمَّع وبنقل عرض نطاق منخفض؛ اللوحة تحتاج تيار WebSocket. واجهة API عامة واحدة لا تخدم الاثنين بشكل مثالي.
- CQRS + مصدر مبني على الأحداث لبيانات GPS — إنتاجية الكتابة (5k/ثانية) لا تتوافق مع استعلامات التحليلات (مسح كامل للجدول على مدى أشهر). فصل نموذج الكتابة (Kafka) عن نماذج القراءة (Redis، ClickHouse) يجعل كلًّا منها مثاليًّا لحالة استخدامه.
- مونوليث معياري للتوزيع — الفريق 12 مهندسًا بخبرة Kubernetes محدودة. وحدتا التوزيع والملفات الشخصية تتغيران معًا كثيرًا. حدود الخدمة الموزعة هنا تضيف كمون شبكة وعبء نشر دون فائدة قابلية توسع عند هذا المستوى من الحمل.
- خدمات لاخادمية للتقارير والصادرات — متقطعة، نادرة، ثقيلة المسح. لا حاجة لخادم دائم. فعّالة من حيث التكلفة.
- خطة خروج Strangler Fig — المونوليث المعياري منظَّم بحيث يمكن استخراج وحدة التوزيع عند نمو الفريق، دون إعادة كتابة.
دورك الآن
طبِّق هذه المنهجية ذاتها على نظام تختاره. ابدأ بالموجز: ما هي أحمال العمل وخصائصها المتمايزة؟ رسِّمها على حدود النطاق. حدِّد الأنماط التي تخدم كل حمل. صرِّح بوضوح بما لن تفعله ولماذا. وثِّق خطة الخروج — كيف تتطور هذه المعمارية مع نمو الحمل أو حجم الفريق؟
تصميم مدروس بمقايضات واضحة مكتوب في صفحة واحدة يساوي أكثر من مخطط مليء بالمصطلحات الرنانة. الهدف دائمًا هو إيصال الثقة لفريقك وأصحاب المصلحة ونفسك في المستقبل.