NestJS — Node.js للمؤسسات

معمارية الخدمات المصغّرة والناقلات

16 دقيقة الدرس 36 من 48

معمارية الخدمات المصغّرة والناقلات

تُفكّك الخدمات المصغّرة (Microservices) التطبيق الضخم إلى خدمات صغيرة مستقلة القابلية للنشر، تتواصل عبر شبكة. يدعم NestJS بناء الخدمات المصغّرة بصورة أصيلة عبر @nestjs/microservices، إذ يوفّر واجهة برمجية موحّدة فوق عدة ناقلات (transporters) — وهي قنوات التواصل بين الخدمات.

لماذا الخدمات المصغّرة؟

  • توسّع مستقل — وسّع الخدمات التي عليها حمل فقط، لا التطبيق كلّه.
  • عزل الأعطال — تعطّل خدمة واحدة لا يُسقط النظام بأكمله.
  • حريّة التقنية — يمكن لكل خدمة استخدام لغة أو قاعدة بيانات مختلفة.
  • استقلالية الفرق — فرق منفصلة تمتلك كل خدمة وتنشرها.
تُضيف الخدمات المصغّرة تعقيدًا تشغيليًّا. اكتشاف الخدمات، وزمن استجابة الشبكة، والتتبّع الموزّع، والاتساق التدريجي تكاليف حقيقية. لا تلجأ إلى هذا النمط إلا عندما تفوق متاعب المونولث (اقتران النشر، عنق زجاجة التوسّع) بوضوح هذه التكاليف.

إنشاء خدمة مصغّرة باستخدام NestFactory.createMicroservice

بدلًا من NestFactory.create()، تستدعي NestFactory.createMicroservice() مُمرّرًا الوحدة الجذر وكائن خيارات الناقل. تستمع الخدمة المصغّرة للرسائل بدلًا من طلبات HTTP:

import { NestFactory } from '@nestjs/core'; import { Transport, MicroserviceOptions } from '@nestjs/microservices'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.createMicroservice<MicroserviceOptions>( AppModule, { transport: Transport.TCP, options: { host: '127.0.0.1', port: 3001 }, }, ); await app.listen(); console.log('Microservice is listening on port 3001'); } bootstrap();

أنماط الرسائل والمعالجات

تستخدم وحدات التحكّم في خدمة مصغّرة @MessagePattern() لتسجيل معالجات الرسائل الواردة. النمط عقد بين المُستدعي والخدمة — سلسلة نصية أو رقم أو كائن:

import { Controller } from '@nestjs/common'; import { MessagePattern, Payload } from '@nestjs/microservices'; @Controller() export class MathController { @MessagePattern({ cmd: 'sum' }) sum(@Payload() data: number[]): number { return data.reduce((a, b) => a + b, 0); } }

للإشعارات من نوع "أرسل وانسَ" (لا يُتوقّع ردّ)، استخدم @EventPattern() بدلًا من @MessagePattern().

ناقل TCP

TCP أبسط الناقلات — تواصل مباشر عبر المقبس بين خدمات على الشبكة نفسها. موثوق ومنخفض الاستجابة، لكنه يستلزم إمكانية الوصول لكلا الخدمتين عبر اسم المضيف أو عنوان IP. استخدمه للخدمات الداخلية المتجاورة.

TCP رائع للتطوير والشبكات الداخلية البسيطة. بالنسبة لأنظمة الإنتاج التي تتطلّب استمرارية الرسائل أو التوزيع الواسع أو إعادة التشغيل، فضّل ناقلًا مبنيًّا على وسيط مثل Redis أو RabbitMQ أو Kafka.

ناقل Redis

يستخدم ناقل Redis نظام نشر/اشتراك في Redis لتمرير الرسائل. لا يحتاج المُستدعي والمعالج إلى وصول مباشر لبعضهما — يتصل كلاهما بخادم Redis. هذا يفصل الخدمات ويُمكّن التوزيع الواسع (مشتركون متعددون لحدث واحد):

// تشغيل الخدمة المصغّرة باستخدام Redis const app = await NestFactory.createMicroservice<MicroserviceOptions>( AppModule, { transport: Transport.REDIS, options: { host: 'localhost', port: 6379 }, }, ); // العميل في خدمة أخرى import { ClientProxy, ClientProxyFactory, Transport } from '@nestjs/microservices'; const client: ClientProxy = ClientProxyFactory.create({ transport: Transport.REDIS, options: { host: 'localhost', port: 6379 }, }); // إرسال رسالة وانتظار الاستجابة (Observable) client.send({ cmd: 'sum' }, [1, 2, 3]).subscribe(result => { console.log('Result:', result); // 6 });

التطبيقات الهجينة (HTTP + خدمة مصغّرة)

يمكن لعملية NestJS واحدة أن تعمل كخادم HTTP ومستمع خدمة مصغّرة في آنٍ واحد. استدعِ app.connectMicroservice() قبل app.startAllMicroservices() وapp.listen():

const app = await NestFactory.create(AppModule); app.connectMicroservice<MicroserviceOptions>({ transport: Transport.TCP, options: { port: 3001 }, }); await app.startAllMicroservices(); await app.listen(3000); // HTTP على :3000، خدمة مصغّرة TCP على :3001
لا تخلط بين التطبيق الهجين ومعمارية الخدمات المصغّرة الحقيقية. الجمع بين HTTP ومستمع الخدمة المصغّرة في عملية واحدة مفيد للتهجير التدريجي أو لخدمة يجب أن تُعرّض واجهتَين. في نظام خدمات مصغّرة من الصفر، ابقِ كل خدمة مُركّزة على مسؤولية واحدة.

الخلاصة

تُشغَّل خدمات NestJS المصغّرة بـ NestFactory.createMicroservice() وإعداد ناقل. يوفّر ناقل TCP تواصلًا مباشرًا عبر المقبس؛ ويفصل ناقل Redis الخدمات عبر وسيط. تُزيَّن المعالجات بـ @MessagePattern() (طلب-استجابة) أو @EventPattern() (أرسل وانسَ). تُشغّل التطبيقات الهجينة HTTP ومستمع الخدمة المصغّرة في العملية نفسها، مما يُتيح التفكيك التدريجي للمونولث.