عندما تتحول الخدمات المصغرة إلى صداع
\nتخيل: لقد نجحت في تقسيم التطبيق المتجانس إلى عشرات الخدمات المصغرة على Node.js. كل خدمة مسؤولة عن مهمتها - المصادقة، كتالوج المنتجات، سلة التسوق، الدفع. كل شيء رائع، حتى يبدأ المرح الحقيقي: الخدمات تتعطل، الطلبات تضيع، المهلات الزمنية تزداد، والسجلات متناثرة عبر خمس لوحات معلومات مختلفة. هل يبدو الأمر مألوفًا؟
\nلقد بدأت بطلبات HTTP بسيطة عبر axios، ولكن الآن كل خدمة تحتاج إلى معرفة عناوين جميع الخدمات الأخرى، ومعالجة إعادة المحاولة، وقواطع الدائرة، وتوزيع الأحمال. يتحول الكود إلى معكرونة من المنطق البنيوي. وهنا يأتي دور Service Mesh - النمط المعماري الذي ينقل كل السحر الشبكي خارج كود جافا سكريبت الخاص بك.
في هذه المقالة، سنشرح كيفية عمل Service Mesh في سياق جافا سكريبت و Node.js، وسنكتب كود تكامل حقيقي مع الحلول الشائعة (Envoy, Istio, Linkerd) وسنفهم متى يكون هذا التعقيد مبررًا. هيا بنا!
\n\nما هو Service Mesh ولماذا يحتاجه مطور جافا سكريبت
\nService Mesh هو طبقة بنية تحتية مخصصة للاتصال بين الخدمات المصغرة. بدلاً من تضمين منطق اكتشاف الخدمات، وتوزيع الأحمال، والتشفير، والمراقبة في كل خدمة بلغة جافا سكريبت، نقوم بنقلها إلى وكيل "sidecar" يعمل بجانب كل مثيل من تطبيقك.
\nبالنسبة لمطور Node.js، هذا يعني:
\n- \n
- كود منطق أعمال نظيف - أنت تكتب فقط معالجات Express/Koa/Fastify، وكل السحر الشبكي مخفي. \n
- توزيع أحمال تلقائي - يتم توزيع الطلبات بين المثيلات دون مكتبات إضافية. \n
- موثوقية مدمجة - إعادة المحاولة، المهلات الزمنية، قواطع الدائرة يتم تكوينها بشكل تصريحي. \n
- مراقبة - التتبع، المقاييس، والسجلات يتم جمعها تلقائيًا. \n
الأكثر روعة: أنت غير مقيد بلغة. Service Mesh يعمل على مستوى الشبكة، لذلك يمكن لخدمة جافا سكريبت الخاصة بك التواصل مع خدمة Go، أو خدمة Python، أو تطبيق Java المتجانس القديم - الوكيل سيجعل كل شيء شفافًا.
\n\nهندسة Service Mesh: حاويات sidecar ومستوى التحكم
\nيتكون Service Mesh الكلاسيكي من جزأين:
\nData Plane (مستوى البيانات)
\nكل خدمة مصغرة لديك (مثل تطبيق Node.js على المنفذ 3000) تعمل مع وكيل sidecar (عادةً Envoy أو Linkerd-proxy). جميع الطلبات الواردة والصادرة تمر عبر هذا الوكيل:
\n// مثال على التوجيه عبر sidecar\n// خدمتك تستمع على localhost:3000\n// Sidecar يستمع على localhost:8080 ويعيد توجيه حركة المرور\n\n// في الإنتاج، لا تصل أبدًا إلى خدمة أخرى مباشرة\n// بدلاً من ذلك، ترسل طلبًا إلى localhost:8080/اسم-الخدمة\n\nconst axios = require('axios');\n\n// بدون Service Mesh (سيء)\n// const userService = 'http://user-service:4000';\n\n// مع Service Mesh (جيد) - نصل إلى sidecar\nconst userService = 'http://localhost:8080'; \n\nasync function getUser(id) {\n const response = await axios.get(`${userService}/users/${id}`);\n return response.data;\n}\nالوكيل يجد تلقائيًا المثيل الصحيح لخدمة user-service، ويوازن الحمل، ويطبق سياسات الأمان.
\n\nControl Plane (مستوى التحكم)
\nهذا هو "عقل" النظام. على سبيل المثال، Istio يستخدم مكونات Pilot و Mixer و Citadel لإدارة التكوين، وجمع القياسات عن بعد، وإصدار الشهادات. تصف قواعد التوجيه في YAML، ويقوم Control Plane بنشرها على جميع وكلاء sidecar.
\n\nمثال عملي: Node.js + Envoy + Istio
\nلنقم بإنشاء إعداد حقيقي. سيكون لدينا خدمتان مصغرتان على Express: order-service و payment-service. بدلاً من ترميز URL الخاص ببعضهما البعض بشكل ثابت، سنستخدم Service Mesh.