Avec le développement continu des applications Internet, il est souvent difficile pour un seul serveur de répondre aux besoins d'une concurrence élevée et d'un trafic important. Afin de résoudre ce problème, des systèmes distribués ont vu le jour. Node.js est un environnement d'exécution JavaScript côté serveur très populaire. Il utilise un modèle d'E/S non bloquant et piloté par les événements et peut gérer des requêtes à haute concurrence et à haut débit. Cependant, la puissance de traitement d'un seul processus Node.js est encore limitée. Par conséquent, cet article présentera comment implémenter un système distribué à l'aide de Node.js.
La distribution fait référence à la décomposition d'une tâche en plusieurs sous-tâches, à l'attribution de ces sous-tâches à différents nœuds de travail pour exécution et à l'exécution de l'intégralité de la tâche en collaboration via la communication réseau. Il existe deux manières principales d'implémenter des systèmes distribués dans Node.js : l'une consiste à utiliser le mode multi-processus et l'autre consiste à utiliser des files d'attente de messages.
1. Utiliser le mode multi-processus
Node.js fournit une API pour créer des processus enfants via le module child_process intégré Nous pouvons facilement créer plusieurs processus enfants pour traiter la même tâche simultanément. En mode multi-processus, chaque sous-processus est indépendant et les données sont échangées entre eux via IPC (communication inter-processus).
Le mode Maître-Ouvrier est l'un des modes multi-processus les plus classiques. Dans ce mode, il existe un processus maître et plusieurs processus travailleurs. Le processus Master est responsable de la gestion de tous les processus Worker, y compris le démarrage, l'arrêt, le redémarrage, etc., tandis que le processus Worker est responsable du traitement des demandes ou des tâches spécifiques.
Dans Node.js, le mode Master-Worker peut être implémenté via le module cluster. Le module cluster est un module avancé encapsulé basé sur le module child_process. Il peut facilement implémenter le mode Master-Worker, comme indiqué ci-dessous :
const cluster = require('cluster'); const http = require('http'); const numCPUs = require('os').cpus().length; if (cluster.isMaster) { console.log(`Master ${process.pid} is running`); // 当主进程被终止时,关闭所有工作进程 process.on('SIGINT', () => { console.log('Received SIGINT. Shutting down workers...'); for (const id in cluster.workers) { cluster.workers[id].kill(); } }); // 根据CPU数量创建工作进程 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 { console.log(`Worker ${process.pid} started`); // Workers可以处理具体的任务,例如下面是创建HTTP服务器的代码 http.createServer((req, res) => { res.writeHead(200); res.end('Hello from worker!'); }).listen(3000); }
Le code ci-dessus montre comment utiliser le module cluster pour créer un processus Master et plusieurs processus Worker. En utilisation réelle, nous pouvons placer des tâches spécifiques et une logique métier telles que des serveurs HTTP dans le processus Worker pour exécution.
Le mode Process Pool est un mode multi-processus plus efficace. Dans ce mode, nous pouvons réutiliser des processus déjà créés pour obtenir une optimisation des performances. Généralement, le nombre de processus dans le pool de processus doit être ajusté dynamiquement en fonction du nombre de processeurs système pour garantir que les demandes peuvent être satisfaites sous une charge élevée.
Node.js n'a pas de module de pool de processus intégré, mais nous pouvons l'implémenter via des modules tiers. Par exemple, le module Generic-pool peut être utilisé pour implémenter facilement un pool de processus Worker, comme indiqué ci-dessous :
const http = require('http'); const pool = require('generic-pool'); const numCPUs = require('os').cpus().length; const workerFactory = { create: function() { return new Promise(resolve => { const worker = child_process.fork('./worker.js'); worker.once('message', msg => { if (msg.ready) { resolve(worker); } }); }); }, destroy: function(worker) { return new Promise(resolve => { worker.once('exit', () => { resolve(); }); worker.send('exit'); }); } }; const workerPool = pool.createPool(workerFactory, { max: numCPUs }); // 创建HTTP服务器 http.createServer(async (req, res) => { const worker = await workerPool.acquire(); worker.send({ type: 'request', path: req.url }); worker.once('message', msg => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(msg)); workerPool.release(worker); }); }).listen(3000);
Le code ci-dessus montre comment utiliser le module Generic-pool pour créer un pool de processus Worker et appeler le Worker dans le pool de processus sur le serveur HTTP pour gérer des requêtes spécifiques.
2. Utiliser la file d'attente des messages
La file d'attente des messages est un mécanisme de communication distribué basé sur un mode de communication asynchrone (non bloquant). En mode file d'attente de messages, nous pouvons envoyer des messages à la file d'attente, et le destinataire récupère le message de la file d'attente et le traite. Par conséquent, les files d'attente de messages peuvent résoudre des problèmes tels que la répartition des tâches et la transmission de données dans les systèmes distribués, et améliorer la fiabilité et l'évolutivité du système.
Il existe de nombreuses implémentations de files d'attente de messages dans Node.js, telles que RabbitMQ, Redis, Kafka, etc. Ici, nous prenons RabbitMQ comme exemple à présenter.
Le modèle producteur-consommateur est un modèle classique de file d'attente de messages. Dans ce mode, le producteur est responsable de l'envoi des messages à la file d'attente et le consommateur est responsable de l'obtention des messages de la file d'attente et de leur traitement.
Dans Node.js, vous pouvez utiliser le module amqp.node pour vous connecter à RabbitMQ et utiliser des concepts tels que les files d'attente et les commutateurs pour implémenter le modèle producteur-consommateur. Voici un exemple simple :
const amqp = require('amqp'); const connection = amqp.createConnection({ host: 'localhost' }); // 连接RabbitMQ服务器 connection.on('ready', function() { console.log('Connected to RabbitMQ'); // 创建消息队列 connection.queue('hello-queue', { durable: true }, function(queue) { console.log('Created queue: ' + queue.name); // 创建消息生产者 setInterval(function() { const message = 'Hello ' + new Date(); console.log('Sending message: ' + message); connection.publish(queue.name, message, { persistent: true }); }, 1000); // 创建消息消费者 queue.subscribe(function(message) { console.log('Received message: ' + message.data.toString()); }); }); });
Le code ci-dessus montre comment utiliser le module amqp.node pour se connecter à un serveur RabbitMQ et créer un producteur et un consommateur. Le producteur envoie un message à la file d'attente toutes les secondes, et le consommateur récupère le message de la file d'attente et le traite.
Le modèle de publication-abonnement est un autre modèle de file d'attente de messages courant. Dans ce mode, il existe un éditeur de messages et plusieurs abonnés aux messages. L'éditeur envoie des messages à un sujet et les abonnés peuvent obtenir des messages du sujet selon leurs propres règles d'abonnement.
Dans Node.js, nous pouvons également utiliser le module amqp.node pour implémenter le mode publication-abonnement. Voici un exemple simple :
const amqp = require('amqp'); const connection = amqp.createConnection({ host: 'localhost' }); // 连接RabbitMQ服务器 connection.on('ready', function() { console.log('Connected to RabbitMQ'); // 创建消息主题 const exchange = connection.exchange('logs', { type: 'fanout' }, function() { console.log('Created exchange: ' + exchange.name); // 创建消息订阅者 connection.queue('', { exclusive: true }, function(queue) { console.log('Created queue: ' + queue.name); queue.bind(exchange, ''); queue.subscribe(function(message) { console.log('Received message: ' + message.data.toString()); }); }); // 创建消息发布者 setInterval(function() { const message = 'Hello ' + new Date(); console.log('Sending message: ' + message); exchange.publish('', message); }, 1000); }); });
Le code ci-dessus montre comment utiliser le module amqp.node pour créer un sujet de message, un abonné au message et un éditeur de message. L'éditeur envoie un message au sujet toutes les secondes, et l'abonné reçoit le message du sujet et le traite.
Résumé
Cet article explique comment utiliser Node.js pour implémenter un système distribué. Dans les applications pratiques, nous pouvons choisir différents mécanismes de communication distribués en fonction des besoins spécifiques de l'entreprise, comme l'utilisation du mode multi-processus ou du mode file d'attente de messages. Quelle que soit la méthode que vous choisissez, vous devez prêter attention à des problèmes tels que la fiabilité, l'évolutivité et la sécurité des systèmes distribués.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!