如何使用Node.js在集群中设置工作人员而不将其放在同一文件中?



我在index.js中有这段代码,我基本上没有从官方Node.js文档中修改过。

const https = require('https');
const fs = require('fs');
const cluster = require('node:cluster');
const numCPUs = require('node:os').cpus().length;
const process = require('node:process');
const livegame = require('./server-livegame');
const matchmaking = require('./server-matchmaking');
//Start ExpressJS
var express = require('express');
const { match } = require('assert');
var app = express();
app.use(express.json());

if (cluster.isPrimary) {
console.log(`Primary ${process.pid} is running`);
for (let i = 0; i< numCPUs; i++){
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
});
}
else
{
new livegame;
new matchmaking;
}

下面是livegame/matchmaking产生错误的简化代码。

const https = require('https');
const fs = require('fs');
const mongoose = require('mongoose');
//Import Models
const LiveMatch = require('./models/livematch');
//Start ExpressJS
var express = require('express');
const { match } = require('assert');
//Interface Security
var options = {
key: fs.readFileSync('key.pem', 'utf8'),
cert: fs.readFileSync('cert.pem', 'utf8')
};
//Server
var httpsServer = https.createServer(options, app);
httpsServer.listen(443);
var app = express();
app.use(express.json());
const chat = 
{
puuid: String,
name: String,
roleID: String,
message: String,
}
app.post(':id/chat', (req,res) => 
{
//something here
});

我将livegame和matchmaking作为单独的.js文件与index.js一起,我调用index.js以编程方式启动它们作为多个实例。然而,这是我得到的错误:

node:events:505
throw er; // Unhandled 'error' event
^
Error: listen EADDRINUSE: address already in use :::443
at Server.setupListenHandle [as _listen2] (node:net:1380:16)
at listenInCluster (node:net:1428:12)
at Server.listen (node:net:1516:7)
at C:Users----DocumentsMGsrcserver-matchmaking.js:25:66
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Emitted 'error' event on Server instance at:
at emitErrorNT (node:net:1407:8)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
code: 'EADDRINUSE',
errno: -4091,
syscall: 'listen',
address: '::',
port: 443
}

根据我目前的进展,我认为问题在于我创造了更多的"用餐空间"。而不是雇佣更多的"工人"。

如何使用集群正确创建具有适当负载平衡的服务器实例?

nodejs中的集群,根据其定义是一组进程,它们都设置为以相同的方式处理传入的连接。主进程使用一种算法在各个集群进程之间旋转传入连接,以便每个进程轮流处理传入连接。这通常在需要增加用于处理传入http请求的cpu数量时使用。默认情况下,一个nodejs进程只在一个线程/CPU中运行你的Javascript。

而且,根据定义,这些集群进程都在做同样的事情(处理传入的http请求),就像你在主进程中做的那样。

如果,你真正想要的是运行不同的代码(让我们说你要做一些繁重的图像处理),你正确地想要得到繁重的CPU处理主线程,所以它可以保持响应传入的连接,然后你会使用WorkerThread(更多的线程在同一个进程)或child_process(更多的进程)。在这两种情况下,你可以在WorkerThread或child_process中运行任何你想要的代码,它可以与你在主nodejs程序中所做的完全不同。

如果潜在的问题是你在web服务器上的POST处理程序中所做的一些处理,那么你是否需要调查上述任何一种方法来扩展完全取决于你在POST处理程序中所做的事情。Nodejs本身,凭借其异步I/O模型(用于网络、文件I/O、数据库访问等),可以在不涉及额外线程或进程的情况下处理大量同时发生的请求。正确编写的异步代码在nodejs中可以很好地扩展。

所以,除非你的进程大量使用CPU(如我上面使用的图像处理示例),否则你应该首先编写好的异步代码,看看它是如何工作的,也许可以对它进行负载测试,以找到瓶颈在哪里。您可能会发现您的瓶颈并不重要(因此您可以获得相当高的规模),或者它们不在可以从上述附加进程中受益的位置,您需要解决瓶颈的特定原因。对于任何高规模的设计,你首先要实现基础,然后大规模测量以了解瓶颈,再次测量,处理瓶颈,再次测量,等等……

猜测瓶颈在哪里通常是非常容易出错的,这会导致你把软件工程放在错误的地方。不猜。测试,测量,发现瓶颈,解决瓶颈。冲洗,起泡,重复。

基于@krtee的帖子:

这里的核心问题是,您实际上试图在同一端口上创建多个进程。

这是真的,你真的很接近节点文档!

// essentially all this stuff 
var httpsServer = https.createServer(options, app);
httpsServer.listen(443);
var app = express();
...
// needs to go in the `else` block of the worker initialization
...
for (let i = 0; i< numCPUs; i++){
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
});
}
else
{
// right bout here.
}

虽然我可能不会使用集群,但我是这样修复这段代码的。

const https = require('https');
const fs = require('fs');
const cluster = require('node:cluster');
const numCPUs = require('node:os').cpus().length;
const process = require('node:process');
const livegame = require('./server-livegame');
const matchmaking = require('./server-matchmaking');
//Start ExpressJS
var express = require('express');
const { match } = require('assert');
var app = express();
app.use(express.json());

if (cluster.isPrimary) {
console.log(`Primary ${process.pid} is running`);
for (let i = 0; i< numCPUs; i++){
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
});
}
else
{
var httpsServer = https.createServer(options, app);
httpsServer.listen(443);
livegame(app);
matchmaking(app);
}

livegame/matchmaking.js

const https = require('https');
const fs = require('fs');
const mongoose = require('mongoose');
//Import Models
const LiveMatch = require('./models/livematch');
//Start ExpressJS
var express = require('express');
const { match } = require('assert');
this.serverLiveGame = function(app)
{
const chat = 
{
puuid: String,
name: String,
roleID: String,
message: String,
}
app.post(':id/chat', (req,res) => 
{
});
};
module.exports = this.serverLiveGame;

代码中不止一个错误:

  1. 只能有一个express()函数处理给定服务器的API。对于在同一端口下运行的任何相关api,该值应该是恒定的。在我的实现中,我只是将变量作为参数传递给函数。
  2. 要将api从另一个.js正确地传递给worker方法,它们必须作为带有适当的module.exports的模块传递。我把必要的代码包装在一个函数中,所以每个api只需要调用一个东西。
  3. 由于我们正在调用一个函数而不是创建一个新对象,所以"new"是不正确的。我们像调用其他函数function(param);

谢谢你的帮助!

相关内容

最新更新