Node.js Cluster Module

Node.js பயன்பாடுகளை பல CPU கோர்களில் அளவிட கற்றுக்கொள்ளுங்கள்

Cluster தொகுதி என்றால் என்ன?

Cluster தொகுதி ஒரே சேவையக போர்ட்டைப் பகிர்ந்து கொள்ளும் பல தொழிலாளர் செயல்முறைகளை உருவாக்க ஒரு வழியை வழங்குகிறது.

Node.js இயல்பாக single-threaded ஆக இருப்பதால், Cluster தொகுதி பல-கோர் அமைப்புகளில் செயல்திறனைக் கணிசமாக மேம்படுத்த உங்கள் பயன்பாட்டை பல CPU கோர்களைப் பயன்படுத்த உதவுகிறது.

ஒவ்வொரு தொழிலாளரும் தங்கள் சொந்த செயல்முறையில் தங்கள் சொந்த இவெண்ட் லூப் மற்றும் நினைவக இடத்தில் இயங்குகிறார்கள், ஆனால் அவர்கள் அனைவரும் ஒரே சேவையக போர்ட்டைப் பகிர்ந்து கொள்கிறார்கள்.

மாஸ்டர் செயல்முறை தொழிலாளர்களை உருவாக்குவதற்கும் உள்வரும் இணைப்புகளை அவர்களுக்கிடையே விநியோகிப்பதற்கும் பொறுப்பாகும்.

Cluster தொகுதியை இறக்குமதி செய்தல்

Cluster தொகுதி Node.js இல் இயல்பாகச் சேர்க்கப்பட்டுள்ளது.

உங்கள் ஸ்கிரிப்ட்டில் அதைத் தேவைப்படுவதன் மூலம் பயன்படுத்தலாம்:

const cluster = require('cluster');
const os = require('os');

// Check if this is the master process
if (cluster.isMaster) {
  console.log(`Master process ${process.pid} is running`);
} else {
  console.log(`Worker process ${process.pid} started`);
}

Clustering எவ்வாறு செயல்படுகிறது

Cluster தொகுதி பல தொழிலாளர் செயல்முறைகளைத் தோற்றுவிக்கும் ஒரு மாஸ்டர் செயல்முறையை உருவாக்குவதன் மூலம் செயல்படுகிறது.

மாஸ்டர் செயல்முறை பயன்பாட்டு குறியீட்டை இயக்காது, ஆனால் தொழிலாளர்களை நிர்வகிக்கிறது.

ஒவ்வொரு தொழிலாளர் செயல்முறையும் உங்கள் பயன்பாட்டு குறியீட்டை சுயாதீனமாக இயக்கும் ஒரு புதிய Node.js நிகழ்வாகும்.

🔧 குறிப்பு:

அடிப்படையில், Cluster தொகுதி புதிய தொழிலாளர்களை உருவாக்க Child Process தொகுதியின் fork() முறையைப் பயன்படுத்துகிறது.

செயல்முறை வகை பொறுப்பு
மாஸ்டர்
  • தொழிலாளர் செயல்முறைகளை உருவாக்குதல் மற்றும் நிர்வகித்தல்
  • தொழிலாளர் ஆரோக்கியத்தைக் கண்காணித்தல்
  • கிராஷ் செய்த தொழிலாளர்களை மீண்டும் தொடங்குதல்
  • சுமை சமநிலை (இணைப்புகளை விநியோகித்தல்)
தொழிலாளர்
  • உண்மையான பயன்பாட்டு குறியீட்டை இயக்குதல்
  • உள்வரும் கோரிக்கைகளைக் கையாளுதல்
  • தரவைச் செயலாக்குதல்
  • வணிக தர்க்கத்தை இயக்குதல்

அடிப்படை கிளஸ்டரை உருவாக்குதல்

ஒவ்வொரு CPU க்கும் தொழிலாளர் செயல்முறைகளுடன் ஒரு கிளஸ்டரை உருவாக்குவதற்கான ஒரு எளிய எடுத்துக்காட்டு இங்கே:

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  // This is the master process

  console.log(`Master ${process.pid} is running`);

  // Fork workers for each CPU core
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  // Listen for worker exits
  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died`);
    // You can fork a new worker to replace the dead one
    console.log('Forking a new worker...');
    cluster.fork();
  });
} else {
  // This is a worker process

  // Create an HTTP server
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Hello from Worker ${process.pid}\n`);

    // Simulate CPU work
    let i = 1e7;
    while (i > 0) { i--; }

  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}

இந்த எடுத்துக்காட்டில்:

மாஸ்டர் செயல்முறை CPU கோர்களின் எண்ணிக்கையைக் கண்டறிகிறது
இது CPU க்கு ஒரு தொழிலாளரை fork செய்கிறது
ஒவ்வொரு தொழிலாளரும் ஒரே போர்ட்டில் (8000) ஒரு HTTP சேவையகத்தை உருவாக்குகிறது
கிளஸ்டர் தொகுதி உள்வரும் இணைப்புகளை தானாக சுமை சமநிலைப்படுத்துகிறது
ஒரு தொழிலாளர் கிராஷ் செய்தால், மாஸ்டர் ஒரு புதியதை உருவாக்குகிறது

தொழிலாளர் தொடர்பு

Child Process தொகுதியில் IPC எவ்வாறு செயல்படுகிறது என்பதைப் போலவே, send() முறை மற்றும் message events ஐப் பயன்படுத்தி மாஸ்டர் மற்றும் தொழிலாளர் செயல்முறைகளுக்கு இடையே தொடர்பு கொள்ளலாம்.

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Track request count for each worker
  const requestCounts = {};

  // Fork workers
  for (let i = 0; i < numCPUs; i++) {
    const worker = cluster.fork();
    requestCounts[worker.id] = 0;

    // Listen for messages from this worker
    worker.on('message', (msg) => {
      if (msg.cmd === 'incrementRequestCount') {
        requestCounts[worker.id]++;
        console.log(`Worker ${worker.id} (pid ${worker.process.pid}) has handled ${requestCounts[worker.id]} requests`);
      }
    });
  }

  // Every 10 seconds, send the request count to each worker
  setInterval(() => {
    for (const id in cluster.workers) {
      cluster.workers[id].send({
        cmd: 'requestCount',
        requestCount: requestCounts[id]
      });
    }
    console.log('Total request counts:', requestCounts);
  }, 10000);

  // Handle worker exit
  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died`);
    // Fork a new worker to replace it
    const newWorker = cluster.fork();
    requestCounts[newWorker.id] = 0;
  });
} else {
  // Worker process
  console.log(`Worker ${process.pid} started`);

  let localRequestCount = 0;

  // Handle messages from the master
  process.on('message', (msg) => {
    if (msg.cmd === 'requestCount') {
      console.log(`Worker ${process.pid} has handled ${msg.requestCount} requests according to master`);
    }
  });

  // Create an HTTP server
  http.createServer((req, res) => {
    // Notify the master that we handled a request
    process.send({ cmd: 'incrementRequestCount' });

    // Increment local count
    localRequestCount++;

    // Send response
    res.writeHead(200);
    res.end(`Hello from Worker ${process.pid}, I've handled ${localRequestCount} requests locally\n`);
  }).listen(8000);
}

பூஜ்ய-கீழேறுதல் மறுதொடக்கம்

கிளஸ்டரிங்கின் முக்கிய நன்மைகளில் ஒன்று கீழேறுதல் இல்லாமல் தொழிலாளர்களை மீண்டும் தொடங்கும் திறனாகும். உங்கள் பயன்பாட்டிற்கான புதுப்பிப்புகளை வெளியிடுவதற்கு இது பயனுள்ளதாக இருக்கும்.

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Store workers
  const workers = [];

  // Fork initial workers
  for (let i = 0; i < numCPUs; i++) {
    workers.push(cluster.fork());
  }

  // Function to restart workers one by one
  function restartWorkers() {
    console.log('Starting zero-downtime restart...');
    
    let i = 0;
    function restartWorker() {
      if (i >= workers.length) {
        console.log('All workers restarted successfully!');
        return;
      }

      const worker = workers[i++];
      console.log(`Restarting worker ${worker.process.pid}...`);

      // Create a new worker
      const newWorker = cluster.fork();
      newWorker.on('listening', () => {
        // Once the new worker is listening, kill the old one
        worker.disconnect();

        // Replace the old worker in our array
        workers[workers.indexOf(worker)] = newWorker;

        // Continue with the next worker
        setTimeout(restartWorker, 1000);
      });
    }

    // Start the recursive process
    restartWorker();
  }
  
  // Simulate a restart after 20 seconds
  setTimeout(restartWorkers, 20000);

  // Handle normal worker exit
  cluster.on('exit', (worker, code, signal) => {
    if (worker.exitedAfterDisconnect !== true) {
      console.log(`Worker ${worker.process.pid} died unexpectedly, replacing it...`);
      const newWorker = cluster.fork();
      workers[workers.indexOf(worker)] = newWorker;
    }
  });
} else {
  // Worker process

  // Create an HTTP server
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Worker ${process.pid} responding, uptime: ${process.uptime().toFixed(2)} seconds\n`);
  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}

இந்த எடுத்துக்காட்டு விளக்குகிறது:

ஆரம்ப தொழிலாளர்களின் தொகுப்பை உருவாக்குதல்
ஒவ்வொரு தொழிலாளரையும் ஒவ்வொன்றாக மாற்றுதல்
பழையதைத் துண்டிக்கும் முன் ஒரு புதிய தொழிலாளர் கேட்பதை உறுதிசெய்தல்
எதிர்பாராத தொழிலாளர் இறப்புகளை நேர்த்தியாகக் கையாளுதல்

சுமை சமநிலை

Cluster தொகுதி தொழிலாளர் செயல்முறைகளுக்கிடையே உள்வரும் இணைப்புகளை விநியோகிப்பதற்கான உள்ளமைக்கப்பட்ட சுமை சமநிலையைக் கொண்டுள்ளது.

இரண்டு முதன்மை உத்திகள் உள்ளன:

Round-Robin (இயல்புநிலை)

விண்டோஸைத் தவிர அனைத்து தளங்களிலும், Node.js ஒரு சுற்று-ராபின் அணுகுமுறையைப் பயன்படுத்தி இணைப்புகளை விநியோகிக்கிறது, இதில் மாஸ்டர் இணைப்புகளை ஏற்றுக்கொண்டு ஒரு வட்ட வரிசையில் தொழிலாளர்களுக்கு விநியோகிக்கிறது.

💻 குறிப்பு:

விண்டோஸில், போர்ட்களை எவ்வாறு கையாள்கிறது என்பதன் காரணமாக சுமை விநியோகம் வித்தியாசமாக செயல்படுகிறது. விண்டோஸில், தொழிலாளர்கள் இணைப்புகளை ஏற்க போட்டியிடுகிறார்கள்.

முதன்மை தொழிலாளர்

cluster.schedulingPolicy ஐ அமைப்பதன் மூலம் ஒவ்வொரு தொழிலாளரும் இணைப்புகளை நேரடியாக ஏற்றுக்கொள்ள அனுமதிக்கலாம்:

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

// Set the scheduling policy to SCHED_NONE (let workers accept connections themselves)
cluster.schedulingPolicy = cluster.SCHED_NONE;

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Fork workers
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died`);
    cluster.fork();
  });
} else {
  // Worker process
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Hello from Worker ${process.pid}\n`);
  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}

பகிரப்பட்ட நிலை

ஒவ்வொரு தொழிலாளரும் தங்கள் சொந்த செயல்முறையில் தங்கள் சொந்த நினைவக இடத்தில் இயங்குவதால், அவர்கள் மாறிகள் மூலம் நேரடியாக நிலையைப் பகிர்ந்து கொள்ள முடியாது. அதற்கு பதிலாக, நீங்கள்:

IPC செய்தியைப் பயன்படுத்தவும் (தொடர்பு எடுத்துக்காட்டில் காட்டப்பட்டுள்ளது)
Redis, MongoDB, அல்லது கோப்பு அமைப்பு போன்ற வெளிப்புற சேமிப்பகத்தைப் பயன்படுத்தவும்
அமர்வு மேலாண்மைக்கான ஒட்டும் சுமை சமநிலையைப் பயன்படுத்தவும்

ஒட்டும் அமர்வுகள் எடுத்துக்காட்டு

ஒட்டும் அமர்வுகள் ஒரே கிளையண்டிலிருந்து வரும் கோரிக்கைகள் எப்போதும் ஒரே தொழிலாளர் செயல்முறைக்குச் செல்லும் என்பதை உறுதிசெய்கின்றன:

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Fork workers
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  // Store worker references by id
  const workers = {};
  for (const id in cluster.workers) {
    workers[id] = cluster.workers[id];
  }

  // Create a server to route connections to workers
  const server = http.createServer((req, res) => {
    // Get client IP
    const clientIP = req.connection.remoteAddress || req.socket.remoteAddress;

    // Simple hash function to determine which worker to use
    const workerIndex = clientIP.split('.').reduce((a, b) => a + parseInt(b), 0) % numCPUs;
    const workerIds = Object.keys(workers);
    const workerId = workerIds[workerIndex];

    // Send the request to the selected worker
    workers[workerId].send('sticky-session:connection', req.connection);

    res.end(`Request routed to worker ${workerId}`);
  }).listen(8000);

  console.log('Master server listening on port 8000');

  // Handle worker exit
  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died`);

    // Remove the dead worker
    delete workers[worker.id];

    // Create a replacement
    const newWorker = cluster.fork();
    workers[newWorker.id] = newWorker;
  });
} else {
  // Worker process - just demonstrates the concept
  // In a real implementation, you'd need more socket handling

  process.on('message', (msg, socket) => {
    if (msg === 'sticky-session:connection' && socket) {
      console.log(`Worker ${process.pid} received sticky connection`);
      
      // In a real implementation, you'd handle the socket here
      // socket.end(`Handled by worker ${process.pid}\n`);
    }
  });

  // Workers would also run their own server
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Direct request to Worker ${process.pid}\n`);
  }).listen(8001);

  console.log(`Worker ${process.pid} started`);
}

இது ஒட்டும் அமர்வுகளின் கருத்தைக் காட்டும் எளிமைப்படுத்தப்பட்ட எடுத்துக்காட்டு. உற்பத்தியில், நீங்கள் பொதுவாக:

மேம்பட்ட ஹேஷிங் அல்காரிதத்தைப் பயன்படுத்தவும்
IP முகவரிகளுக்குப் பதிலாக குக்கீகள் அல்லது பிற அமர்வு அடையாளங்காட்டிகளைப் பயன்படுத்தவும்
சாக்கெட் இணைப்புகளை மிகவும் கவனமாக கையாளவும்

தொழிலாளர் வாழ்க்கைச் சுழற்சி

உங்கள் கிளஸ்டரை சரியாக நிர்வகிப்பதற்கு தொழிலாளர் வாழ்க்கைச் சுழற்சியைப் புரிந்துகொள்வது முக்கியம்:

நிகழ்வு விளக்கம்
fork ஒரு புதிய தொழிலாளர் fork செய்யப்படும் போது வெளியிடப்படுகிறது
online தொழிலாளர் இயங்கும் போது மற்றும் செய்திகளைச் செயலாக்கத் தயாராக இருக்கும் போது வெளியிடப்படுகிறது
listening தொழிலாளர் இணைப்புகளுக்குக் கேட்கத் தொடங்கும் போது வெளியிடப்படுகிறது
disconnect ஒரு தொழிலாளரின் IPC சேனல் துண்டிக்கப்படும் போது வெளியிடப்படுகிறது
exit ஒரு தொழிலாளர் செயல்முறை வெளியேறும் போது வெளியிடப்படுகிறது
const cluster = require('cluster');
const http = require('http');

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Fork a worker
  const worker = cluster.fork();

  // Listen for all worker lifecycle events
  worker.on('fork', () => {
    console.log(`Worker ${worker.process.pid} is being forked`);
  });

  worker.on('online', () => {
    console.log(`Worker ${worker.process.pid} is online`);
  });

  worker.on('listening', (address) => {
    console.log(`Worker ${worker.process.pid} is listening on port ${address.port}`);
  });

  worker.on('disconnect', () => {
    console.log(`Worker ${worker.process.pid} has disconnected`);
  });

  worker.on('exit', (code, signal) => {
    console.log(`Worker ${worker.process.pid} exited with code ${code} and signal ${signal}`);

     if (signal) {
      console.log(`Worker was killed by signal: ${signal}`);
    } else if (code !== 0) {
      console.log(`Worker exited with error code: ${code}`);
    } else {
      console.log('Worker exited successfully');
    }
  });

  // After 10 seconds, gracefully disconnect the worker
  setTimeout(() => {
    console.log('Gracefully disconnecting worker...');
    worker.disconnect();
  }, 10000);

} else {
  // Worker process
  console.log(`Worker ${process.pid} started`);

  // Create an HTTP server
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Hello from Worker ${process.pid}\n`);
  }).listen(8000);

  // If worker is disconnected, close the server
  process.on('disconnect', () => {
    console.log(`Worker ${process.pid} disconnected, closing server...`);
    // In a real application, you'd want to close all connections and clean up resources
    process.exit(0);
  });
}

நேர்த்தியான அணைப்பு

உங்கள் தொழிலாளர் செயல்முறைகள் வெளியேறும் முன் இருக்கும் கோரிக்கைகளை முடிக்க அனுமதிக்க ஒரு நேர்த்தியான அணைப்பு முக்கியமானது.

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Fork workers
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  // Handle termination signals
  process.on('SIGTERM', () => {
    console.log('Master received SIGTERM, initiating graceful shutdown...');

    // Notify all workers to finish their work and exit
    Object.values(cluster.workers).forEach(worker => {
      console.log(`Sending SIGTERM to worker ${worker.process.pid}`);
      worker.send('shutdown');
    });

    // Set a timeout to force-kill workers if they don't exit gracefully
    setTimeout(() => {
      console.log('Some workers did not exit gracefully, forcing shutdown...');
      Object.values(cluster.workers).forEach(worker => {
        if (!worker.isDead()) {
          console.log(`Killing worker ${worker.process.pid}`);
          worker.process.kill('SIGKILL');
        }
    });

    // Exit the master
    console.log('All workers terminated, exiting master...');
    process.exit(0);
  }, 5000);
  });

  // Handle worker exits
  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} exited (${signal || code})`);

    // If all workers have exited, exit the master
    if (Object.keys(cluster.workers).length === 0) {
      console.log('All workers have exited, shutting down master...');
      process.exit(0);
    }
  });

  // Log to show the master is ready
  console.log(`Master ${process.pid} is ready with ${Object.keys(cluster.workers).length} workers`);
  console.log('Send SIGTERM to the master process to initiate graceful shutdown');

} else {
  // Worker process
  console.log(`Worker ${process.pid} started`);

  // Track if we're shutting down
  let isShuttingDown = false;
  let activeConnections = 0;

  // Create HTTP server
  const server = http.createServer((req, res) => {
     // Track active connection
     activeConnections++;

    // Simulate a slow response
    setTimeout(() => {
      res.writeHead(200);
      res.end(`Hello from Worker ${process.pid}\n`);

      // Connection complete
      activeConnections--;

      // If we're shutting down and no active connections, close the server
      if (isShuttingDown && activeConnections === 0) {
        console.log(`Worker ${process.pid} has no active connections, closing server...`);
        server.close(() => {
          console.log(`Worker ${process.pid} closed server, exiting...`);
          process.exit(0);
        });
      }
    }, 2000);
  });

  // Start server
  server.listen(8000);

  // Handle shutdown message from master
  process.on('message', (msg) => {
     if (msg === 'shutdown') {
      console.log(`Worker ${process.pid} received shutdown message, stopping new connections...`);

      // Set shutdown flag
      isShuttingDown = true;

      // Stop accepting new connections
      server.close(() => {
        console.log(`Worker ${process.pid} closed server`);

      // If no active connections, exit immediately
      if (activeConnections === 0) {
        console.log(`Worker ${process.pid} has no active connections, exiting...`);
        process.exit(0);
      } else {
        console.log(`Worker ${process.pid} waiting for ${activeConnections} connections to finish...`);
      }
    });
  }
  });

  // Also handle direct termination signal
  process.on('SIGTERM', () => {
    console.log(`Worker ${process.pid} received SIGTERM directly`);
    // Use the same shutdown logic
    isShuttingDown = true;
    server.close(() => process.exit(0));
  });
}

சிறந்த நடைமுறைகள்

தொழிலாளர்களின் எண்ணிக்கை: பெரும்பாலான சந்தர்ப்பங்களில், CPU கோருக்கு ஒரு தொழிலாளரை உருவாக்கவும்
நிலையற்ற வடிவமைப்பு: கிளஸ்டர்களுடன் திறம்பட வேலை செய்ய உங்கள் பயன்பாட்டை நிலையற்றதாக வடிவமைக்கவும்
நேர்த்தியான அணைப்பு:இணைப்புகளை கைவிடாமல் இருக்க சரியான அணைப்பு கையாளுதலை செயல்படுத்தவும்
தொழிலாளர் கண்காணிப்பு:கிராஷ் செய்த தொழிலாளர்களை விரைவாகக் கண்காணித்து மாற்றவும்
தரவுத்தள இணைப்புகள்:ஒவ்வொரு தொழிலாளருக்கும் தனிச் சொந்த இணைப்பு குளம் உள்ளது, எனவே தரவுத்தள இணைப்புகளைத் தகுந்தவாறு கட்டமைக்கவும்
பகிரப்பட்ட வளங்கள்:தொழிலாளர்களுக்கிடையே பகிரப்படும் வளங்களுடன் (கோப்பு பூட்டுகள் போன்றவை) கவனமாக இருங்கள்
தொழிலாளர்களை இலகுவாக வைத்திருங்கள்:தொழிலாளர் செயல்முறைகளில் தேவையற்ற நினைவக பயன்பாட்டைத் தவிர்க்கவும்

⚠️ எச்சரிக்கை:

பல தொழிலாளர்களைப் பயன்படுத்தும் போது கோப்பு-அடிப்படையிலான பூட்டு மற்றும் பிற பகிரப்பட்ட வளங்களுடன் கவனமாக இருங்கள். ஒற்றை-செயல்முறை பயன்பாட்டில் பாதுகாப்பான செயல்பாடுகள் பல தொழிலாளர்களுடன் போட்டி நிலைமைகளை ஏற்படுத்தக்கூடும்.

Cluster தொகுதிக்கான மாற்றுகள்

Cluster தொகுதி சக்திவாய்ந்ததாக இருந்தாலும், பல கோர்களில் Node.js பயன்பாடுகளை இயக்குவதற்கு மாற்றுகள் உள்ளன:

அணுகுமுறை விளக்கம் பயன்பாட்டு வழக்கு
PM2 உள்ளமைக்கப்பட்ட சுமை சமநிலை மற்றும் கிளஸ்டரிங்குடன் Node.js பயன்பாடுகளுக்கான ஒரு செயல்முறை மேலாளர் வலுவான செயல்முறை மேலாண்மை தேவைப்படும் உற்பத்தி பயன்பாடுகள்
சுமை சமநிலை Nginx போன்ற சுமை சமநிலையின் பின்னால் பல Node.js நிகழ்வுகளை இயக்குதல் பல சேவையகங்கள் அல்லது கொள்கலன்களில் சுமையை விநியோகித்தல்
தொழிலாளர் நூல்கள் CPU-தீவிர பணிகளுக்கான இலகுவான நூலிடல் (Node.js >= 10.5.0) ஒற்றை செயல்முறைக்குள் CPU-தீவிர செயல்பாடுகள்
கொள்கலன்கள் பல கொள்கலனாக்கப்பட்ட நிகழ்வுகளை இயக்குதல் (Docker மற்றும் Kubernetes உடன்) நவீன கிளவுட் சூழல்களில் அளவிடக்கூடிய, விநியோகிக்கப்பட்ட பயன்பாடுகள்

மேம்பட்ட சுமை சமநிலை உத்திகள்

Cluster தொகுதியின் இயல்புநிலை சுற்று-ராபின் சுமை சமநிலை பல பயன்பாடுகளுக்கு நன்றாக வேலை செய்யும் போது, குறிப்பிட்ட பயன்பாட்டு வழக்குகளுக்கு மேம்பட்ட உத்திகள் தேவைப்படலாம்.

1. எடை சுற்று-ராபின்

const cluster = require('cluster');
const http = require('http');
const os = require('os');
if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Create workers with different weights
  const workerWeights = [3, 2, 1]; // First worker gets 3x more load than the last
  const workers = [];

  // Create workers based on weights
  workerWeights.forEach((weight, index) => {
    for (let i = 0; i < weight; i++) {
      const worker = cluster.fork({ WORKER_WEIGHT: weight });
      worker.weight = weight;
      workers.push(worker);
    }
  });

  // Track the next worker to use
  let workerIndex = 0;

  // Create a load balancer server
  http.createServer((req, res) => {
    // Simple round-robin with weights
    const worker = workers[workerIndex++ % workers.length];
    worker.send('handle-request', req.socket);
  }).listen(8000);

} else {   // Worker code
  process.on('message', (message, socket) => {
    if (message === 'handle-request' && socket) {
      // Handle the request
      socket.end(`Handled by worker ${process.pid}\n`);
    }
  });
}

2.குறைந்த இணைப்புகள்

const cluster = require('cluster');
const http = require('http');
if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Create workers and track their connection counts
  const workers = [];
  const numCPUs = require('os').cpus().length;

  for (let i = 0; i < numCPUs; i++) {
    const worker = cluster.fork();
    worker.connectionCount = 0;
    workers.push(worker);

    // Track worker connections
    worker.on('message', (msg) => {       if (msg.type === 'connection') {         worker.connectionCount = msg.count;       }     });
  }
  // Create load balancer
  http.createServer((req, res) => {
    // Find worker with least connections
    let minConnections = Infinity;
    let selectedWorker = null;

    for (const worker of workers) {
      if (worker.connectionCount < minConnections) {
        minConnections = worker.connectionCount;
        selectedWorker = worker;
      }
    }

    if (selectedWorker) {
      selectedWorker.send('handle-request', req.socket);
    }
  }).listen(8000);
}

செயல்திறன் கண்காணிப்பு மற்றும் அளவீடுகள்

ஆரோக்கியமான பயன்பாட்டை பராமரிப்பதற்கு உங்கள் கிளஸ்டரின் செயல்திறனைக் கண்காணிப்பது முக்கியமானது. அடிப்படை அளவீடுகள் சேகரிப்பைச் செயல்படுத்துவது எப்படி என்பது இங்கே:

const cluster = require('cluster');
const os = require('os');
const promClient = require('prom-client');
if (cluster.isMaster) {
  // Create metrics registry
  const register = new promClient.Registry();
  promClient.collectDefaultMetrics({ register });

  // Custom metrics
  const workerRequests = new promClient.Counter({
    name: 'worker_requests_total',
    help: 'Total requests handled by worker',
    labelNames: ['worker_pid']
  });
register.registerMetric(workerRequests);

  // Fork workers
  for (let i = 0; i < os.cpus().length; i++) {
    const worker = cluster.fork();
    worker.on('message', (msg) => {
      if (msg.type === 'request_processed') {
        workerRequests.inc({ worker_pid: worker.process.pid });
      }
    });
  }

  // Expose metrics endpoint
  require('http').createServer(async (req, res) => {
    if (req.url === '/metrics') {
      res.setHeader('Content-Type', register.contentType);
      res.end(await register.metrics());
    }
  }).listen(9090);
} else {
  // Worker code
  let requestCount = 0;

  require('http').createServer((req, res) => {
    requestCount++;
    process.send({ type: 'request_processed' });
    res.end(`Request ${requestCount} handled by worker ${process.pid}\n`);
  }).listen(8000);
}

கண்காணிக்க வேண்டிய முக்கிய அளவீடுகள்

கோரிக்கை விகிதம்: ஒரு தொழிலாளருக்கு வினாடிக்கு கோரிக்கைகள்
பிழை விகிதம்: வினாடிக்கு பிழை பதில்கள்
பதில் நேரம்: P50, P90, P99 பதில் நேரங்கள்
CPU பயன்பாடு: ஒரு தொழிலாளருக்கு CPU பயன்பாடு
நினைவக பயன்பாடு: ஒரு தொழிலாளருக்கு Heap மற்றும் RSS நினைவகம்
இவெண்ட் லூப் பின்தங்கல்: இவெண்ட் லூப்பில் தாமதம்

கொள்கலன் ஒருங்கிணைப்பு

Docker மற்றும் Kubernetes போன்ற கொள்கலனாக்கப்பட்ட சூழல்களில் இயக்கும் போது, இந்த சிறந்த நடைமுறைகளைக் கவனியுங்கள்:

1. செயல்முறை மேலாண்மை

// Dockerfile example for a Node.js cluster app
FROM node:16-slim

WORKDIR /app
COPY package*.json ./
RUN npm install --production

# Copy application code
COPY . .

# Use the node process as PID 1 for proper signal handling
CMD ["node", "cluster.js"]

# Health check
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8080/health || exit 1

2. Kubernetes Deployment

# k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-cluster-app
spec:
  replicas: 3 # Number of pods
  selector:
    matchLabels:
      app: node-cluster
  template:
    metadata:
      labels:
        app: node-cluster
    spec:
      containers:
      - name: node-app
        image: your-image:latest
        ports:
          - containerPort: 8000
        resources:
          requests:
            cpu: "500m"
            memory: "512Mi"
        limits:
          cpu: "1000m"
          memory: "1Gi"
        livenessProbe:
          httpGet:
            path: /health
            port: 8000
            initialDelaySeconds: 5
            periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8000
            initialDelaySeconds: 5
            periodSeconds: 10

பொதுவான பொறிகுழிகள் மற்றும் தீர்வுகள்

1. தொழிலாளர்களில் நினைவக கசிவுகள்

சிக்கல்: தொழிலாளர் செயல்முறைகளில் நினைவக கசிவுகள் படிப்படியான நினைவக வளர்ச்சியை ஏற்படுத்தும்.

தீர்வு: நினைவக பயன்பாட்டின் அடிப்படையில் தொழிலாளர் மறுசுழற்சியை செயல்படுத்தவும்.

// In worker process
const MAX_MEMORY_MB = 500; // Max memory in MB before recycling

function checkMemory() {
  const memoryUsage = process.memoryUsage();
  const memoryMB = memoryUsage.heapUsed / 1024 / 1024;

  if (memoryMB > MAX_MEMORY_MB) {
    console.log(`Worker ${process.pid} memory ${memoryMB.toFixed(2)}MB exceeds limit, exiting...`);
    process.exit(1); // Let cluster restart the worker
  }
}

// Check memory every 30 seconds
setInterval(checkMemory, 30000);

2. Thunder Herd சிக்கல்

சிக்கல்: மறுதொடக்கத்திற்குப் பிறகு அனைத்து தொழிலாளர்களும் ஒரே நேரத்தில் இணைப்புகளை ஏற்றுக்கொள்கிறார்கள்.

தீர்வு: staggered startup ஐ செயல்படுத்தவும்.

// In master process
if (cluster.isMaster) {
  const numWorkers = require('os').cpus().length;

  function forkWorker(delay) {
    setTimeout(() => {
      const worker = cluster.fork();
      console.log(`Worker ${worker.process.pid} started after ${delay}ms delay`);
    }, delay);
  }

  // Stagger worker starts by 1 second
  for (let i = 0; i < numWorkers; i++) {
    forkWorker(i * 1000);
  }
}

3. தொழிலாளர் பட்டினி

சிக்கல்: சில தொழிலாளர்கள் மற்றவர்களை விட அதிக சுமையைப் பெறுகிறார்கள்.

தீர்வு: சரியான சுமை சமநிலை மற்றும் கண்காணிப்பை செயல்படுத்தவும்.

// Track request distribution
const requestDistribution = new Map();

// In master process
if (cluster.isMaster) {
  // ...

  // Monitor request distribution
  setInterval(() => {
    console.log('Request distribution:');
    requestDistribution.forEach((count, pid) => {
      console.log(` Worker ${pid}: ${count} requests`);
    });
  }, 60000);

  // Track requests per worker
  cluster.on('message', (worker, message) => {
    if (message.type === 'request_handled') {
      const count = requestDistribution.get(worker.process.pid) || 0;
      requestDistribution.set(worker.process.pid, count + 1);
    }
  });
}

சுருக்கம்

Node.js Cluster தொகுதி பல CPU கோர்களில் உங்கள் பயன்பாட்டை அளவிட ஒரு திறமையான வழியை வழங்குகிறது:

பல தொழிலாளர் செயல்முறைகளை நிர்வகிக்கும் ஒரு மாஸ்டர் செயல்முறையை உருவாக்குகிறது
தொழிலாளர்கள் ஒரே சேவையக போர்ட்டைப் பகிர்ந்து கொள்கிறார்கள், சுமை சமநிலைப்படுத்தலை அனுமதிக்கிறார்கள்
பயன்பாட்டு செயல்திறன் மற்றும் நெகிழ்வுத்தன்மையை மேம்படுத்துகிறது
பூஜ்ய-கீழேறுதல் மறுதொடக்கங்கள் மற்றும் நேர்த்தியான அணைப்புகளை இயலுமைப்படுத்துகிறது
மாஸ்டர் மற்றும் தொழிலாளர்களுக்கு இடையே தொடர்புக்கு IPC ஐப் பயன்படுத்துகிறது

கிளஸ்டரிங்கைப் புரிந்துகொண்டு சரியாகச் செயல்படுத்துவதன் மூலம், கிடைக்கக்கூடிய அனைத்து CPU வளங்களையும் திறம்படப் பயன்படுத்தும் உயர்-செயல்திறன், நம்பகமான Node.js பயன்பாடுகளை உருவாக்க முடியும்.

பயிற்சி

சரியான தொகுதி பெயரை தேர்வு செய்யவும்.

The ______ module allows you to create child processes that run simultaneously and share the same server port.

child_process
✗ தவறு! "child_process" தொகுதி குழந்தை செயல்முறைகளை உருவாக்குகிறது, ஆனால் அவை ஒரே போர்ட்டைப் பகிர்ந்து கொள்ளாது
worker_threads
✗ தவறு! "worker_threads" தொகுதி நூல்களை உருவாக்குகிறது, குழந்தை செயல்முறைகளை அல்ல, மேலும் அவை போர்ட்டுகளைப் பகிர்ந்து கொள்ளாது
cluster
✓ சரி! "cluster" தொகுதி ஒரே சேவையக போர்ட்டைப் பகிர்ந்து கொள்ளும் குழந்தை செயல்முறைகளை உருவாக்க உங்களை அனுமதிக்கிறது
os
✗ தவறு! "os" தொகுதி இயக்க முறைமை-தொடர்பான தகவல்களை வழங்குகிறது, ஆனால் குழந்தை செயல்முறைகளை உருவாக்காது