🟩 شرح Node.js

الأداء والتوسّع

مشكلة الخيط الواحد

Node أحادي الخيط — عملية حسابية ثقيلة تحجب حلقة الأحداث فيتجمّد الخادم لكل المستخدمين. الحلّ: توزيع العمل.

التسجيل (Logging)

سجّل الأحداث المهمّة لتتبّع المشاكل في الإنتاج. مكتبات شائعة: Winston، Pino:

// npm install winston
import winston from "winston";

const logger = winston.createLogger({
  level: "info",
  transports: [new winston.transports.Console()],
});

logger.info("الخادم بدأ");
logger.error("فشل الاتصال بقاعدة البيانات");

المراقبة (Monitoring)

راقب الذاكرة والمعالج وزمن الاستجابة. أدوات: PM2، أو خدمات مثل Datadog.

console.log(process.memoryUsage());   // استهلاك الذاكرة
console.log(process.uptime());        // مدّة التشغيل

Cluster — استغلال كل الأنوية

ينسخ التطبيق على كل أنوية المعالج ليخدم طلبات أكثر:

import cluster from "cluster";
import os from "os";

if (cluster.isPrimary) {
  const cpus = os.cpus().length;
  for (let i = 0; i < cpus; i++) {
    cluster.fork();   // عملية لكل نواة
  }
} else {
  // كل عامل يشغّل الخادم
  startServer();
}

Worker Threads — للحسابات الثقيلة

ينفّذ العمليات الثقيلة في خيط منفصل دون حجب الرئيسي:

import { Worker } from "worker_threads";

const worker = new Worker("./heavy-task.js");
worker.on("message", (result) => {
  console.log("النتيجة:", result);
});

Child Process — تشغيل أوامر خارجية

import { exec } from "child_process";

exec("ls -la", (err, stdout) => {
  console.log(stdout);
});

الخدمات المصغّرة (Microservices)

بدل تطبيق واحد ضخم، نقسّمه إلى خدمات صغيرة مستقلّة (مستخدمون، دفع، إشعارات) تتواصل عبر APIs أو طوابير رسائل. مزايا: توسّع وصيانة أسهل لكل جزء. عيوب: تعقيد أكبر في الإدارة.

نصائح أداء عملية

  • خزّن مؤقّتًا (Cache) النتائج المتكرّرة (Redis).
  • استخدم التدفّقات للملفات الكبيرة.
  • تجنّب حجب حلقة الأحداث بالحسابات الثقيلة.
  • اضغط الردود (gzip) لتقليل الحجم.

أخطاء شائعة

  • التوسّع المبكر (Microservices) لمشروع صغير — يضيف تعقيدًا بلا داعٍ.
  • تشغيل حسابات ثقيلة في الخيط الرئيسي بدل Worker Threads.

🎯 التالي: الخلاصة وخطواتك بعد Node.js.