ميكروسيرفيسات جافا سكريبت: الهندسة المعمارية والممارسة المتقدمة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

ميكروسيرفيسات جافا سكريبت: من التطبيق المتجانس إلى النظام الموزع



الانتقال من التطبيق المتجانس إلى الهندسة المعمارية للميكروسيرفيسات ليس مجرد إعادة هيكلة تقنية، بل هو تغيير في فلسفة التطوير. على المستوى المتقدم للعمل مع Node.js، نواجه الحاجة ليس فقط لتقسيم الكود إلى وحدات، بل لإنشاء نظام موزع مستقر وقابل للتوسع ومتحمل للأخطاء. في هذه المقالة، سنناقش القرارات المعمارية الرئيسية والأنماط العملية التي ستساعدك في بناء ميكروسيرفيسات جاهزة للإنتاج بلغة جافا سكريبت.



التحديات الرئيسية التي يواجهها المطور: مزامنة البيانات بين الخدمات، والحفاظ على سلامة المعاملات، واكتشاف الخدمات، والتواصل الفعال. خطأ في مرحلة التصميم يمكن أن يؤدي إلى فوضى في بيئة الإنتاج. دعنا نرى كيف نتجنب ذلك.



1. التواصل بين الخدمات: RabbitMQ و gRPC



في عالم الميكروسيرفيسات، اختيار بروتوكول الاتصال هو أمر أساسي. بالنسبة لـ Node.js، هناك نهجان شائعان: قائمة انتظار الرسائل غير المتزامنة (RabbitMQ) و RPC المتزامن عالي الأداء (gRPC).



قائمة انتظار غير متزامنة (RabbitMQ)

تُستخدم للهندسة المعمارية الموجهة بالأحداث. خدمة المنتج لا تنتظر الرد، بل تنشر الحدث. هذا يقلل من الاقتران. لنلقِ نظرة على مثال لإرسال طلب إلى خدمة التوصيل.



// خدمة "الطلبات" — المنتجconst amqp = require('amqplib');

async function publishOrderCreated(order) { const connection = await amqp.connect('amqp://rabbitmq:5672'); const channel = await connection.createChannel(); const exchange = 'order.events'; await channel.assertExchange(exchange, 'topic', { durable: true });

channel.publish(exchange, 'order.created', Buffer.from(JSON.stringify(order)), { persistent: true });

console.log(`[x] Sent order: ${order.id}`); await channel.close(); await connection.close();}

// الاستدعاء عند إنشاء الطلبpublishOrderCreated({ id: '123', userId: '456', amount: 1500 });


خدمة المستهلك (التوصيل) تشترك في قائمة الانتظار:



// خدمة "التوصيل" — المستهلكconst amqp = require('amqplib');

async function consumeOrders() { const connection = await amqp.connect('amqp://rabbitmq:5672'); const channel = await connection.createChannel(); const exchange = 'order.events'; await channel.assertExchange(exchange, 'topic', { durable: true });

const q = await channel.assertQueue('', { exclusive: true }); await channel.bindQueue(q.queue, exchange, 'order.created');

channel.consume(q.queue, (msg) => { if (msg.content) { const order = JSON.parse(msg.content.toString()); console.log(`[x] Received order: ${order.id}`); // منطق إنشاء التوصيل channel.ack(msg); } });}

consumeOrders();


gRPC المتزامن

للسيناريوهات التي تتطلب ردًا فوريًا (مثل التحقق من رصيد المستخدم)، يوفر gRPC كتابة صارمة وسرعة عالية عبر HTTP/2. نحدد ملف proto:



// user.protoservice UserService {  rpc GetUserBalance (UserRequest) returns (UserResponse);}

message UserRequest { string user_id = 1;}

message UserResponse { double balance = 1;}


تنفيذ الخادم على Node.js:



const grpc = require('@grpc/grpc-js');const protoLoader = require('@grpc/proto-loader');const PROTO_PATH = './user.proto';

const packageDefinition = protoLoader.loadSync(PROTO_PATH, { keepCase: true, longs: String, enums: String, defaults: true, oneofs: true});const userProto = grpc.loadPackageDefinition(packageDefinition).userservice;

function getBalance(call, callback) { const userId = call.request.user_id; // محاكاة طلب إلى قاعدة البيانات const balance = userId === '456' ? 5000 : 0; callback(null, { balance });}

const server = new grpc.Server();server.addSe

المدونات

توصيات الكتب