ميكروسيرفيسات بلغة JavaScript: الهندسة والممارسة مع Node.js
أصبحت بنية الميكروسيرفيسات المعيار الفعلي لبناء تطبيقات ويب قابلة للتوسع وتحمل الأخطاء. لغة JavaScript، وخاصة بيئة التشغيل Node.js، مثالية لهذا النموذج بفضل النموذج غير المتزامن، والنظام البيئي الغني، وسرعة التطوير العالية. في هذه المقالة، سنشرح كيفية تصميم وتنفيذ الميكروسيرفيسات بلغة JavaScript، وسننظر في القرارات المعمارية الرئيسية ونكتب أمثلة عملية للكود.
1. أساسيات بنية الميكروسيرفيسات على Node.js
الميكروسيرفيسات هي نهج يتم فيه تقسيم التطبيق إلى خدمات صغيرة مترابطة بشكل ضعيف. كل خدمة مسؤولة عن وظيفة تجارية محددة (مثل إدارة المستخدمين، معالجة الطلبات، أو إرسال الإشعارات) ويمكن تطويرها ونشرها وتوسيع نطاقها بشكل مستقل. تسمح Node.js بهندستها القائمة على الأحداث بإنشاء خدمات خفيفة وسريعة تعالج آلاف الطلبات المتزامنة بكفاءة.
المزايا الرئيسية لاستخدام JavaScript للميكروسيرفيسات:
- لغة موحدة — يتم كتابة الواجهة الأمامية والخلفية بنفس اللغة، مما يبسط انتقال المطورين بين الطبقات.
- أداء عالٍ — الإدخال/الإخراج غير المحظور في Node.js مناسب تمامًا للميكروسيرفيسات التي تتواصل غالبًا عبر الشبكة.
- نظام بيئي غني — يوفر npm مكتبات جاهزة لإنشاء REST API، والعمل مع قوائم الانتظار، وقواعد البيانات، والحاويات.
2. التصميم والتواصل بين الخدمات
عند تصميم الميكروسيرفيسات بلغة JavaScript، من المهم تحديد كيفية تواصل الخدمات مع بعضها البعض. هناك طريقتان رئيسيتان:
- التواصل المتزامن (REST/gRPC) — ترسل الخدمة A طلب HTTP إلى الخدمة B وتنتظر الرد. سهولة التنفيذ، لكنها تخلق ارتباطًا قويًا وقد تؤدي إلى أعطال متتالية.
- التواصل غير المتزامن (قوائم انتظار الرسائل) — تتبادل الخدمات الرسائل عبر وسيط (RabbitMQ, Kafka). يضمن هذا ارتباطًا ضعيفًا، ويزيد من تحمل الأخطاء، ويسمح بتوسيع نطاق المعالجات بسهولة.
لننظر في مثال لخدمة مصغرة بسيطة لإدارة الطلبات باستخدام Express (REST API) و RabbitMQ (إرسال الإشعارات غير المتزامن).
مثال: REST API لخدمة الطلبات المصغرة
const express = require('express');const amqp = require('amqplib');const app = express();app.use(express.json());
// تخزين الطلبات (في مشروع حقيقي — قاعدة بيانات)const orders = [];
// إنشاء طلبapp.post('/orders', async (req, res) => { const { userId, product, quantity } = req.body; const order = { id: Date.now(), userId, product, quantity, status: 'created' }; orders.push(order); // إرسال الحدث إلى قائمة الانتظار لإشعار المستخدم const connection = await amqp.connect('amqp://localhost'); const channel = await connection.createChannel(); await channel.assertQueue('order_notifications'); channel.sendToQueue('order_notifications', Buffer.from(JSON.stringify(order))); res.status(201).json(order);});
// الحصول على قائمة الطلباتapp.get('/orders', (req, res) => { res.json(orders);});
app.listen(3001, () => console.log('Order service running on port 3001'));مثال: خدمة الإشعارات (مستهلك غير متزامن)
const amqp = require('amqplib');
async function consumeNotifications() { const connection = await amqp.connect('amqp://localhost'); const channel = await connection.createChannel(); await channel.assertQueue('order_notifications'); channel.consume('order_notifications', (msg) => { const order = JSON.parse(msg.content.toString()); console.log(`Sending notification for order ${order.id} to user ${order.userId}`); // هنا يمكن استدعاء API خارجي (email,