NodeJS部分疑惑

NodeJS部分疑惑

Nodejs貌似启动就是单核单进程的

那么我启动node后,需要用多核怎么办?

我看外面好像是凯多个instance,用nginx在实现绑定

那么又有疑问了,他们是相对独立的吗?那么如何做数据共享呢?

还有种方式是fork多个子进程(是子进程吗?),然后绑定到同一个端口上,那么他们的数据是如何共享的?

假设我有NodeA,NodeB,NodeC3个进程都绑定在同一个端口3000上

那么NodeA里面有个Array,NodeB和NodeC知道吗?

那么如果客户端访问3000,是访问有NodeA,NodeB,NodeC3其中哪一个


7 回复

NodeJS部分疑惑

启动单核单进程的问题

确实,Node.js 默认是以单线程运行的。这意味着在一个进程中,它只能利用一个CPU核心。然而,Node.js 提供了一些机制来利用多核CPU的优势。

使用多个实例

一种常见的方法是通过启动多个Node.js实例,并使用负载均衡器(如Nginx)来分发请求。每个实例都会运行在不同的端口上,负载均衡器会根据配置将请求分配给不同的实例。

示例:

# 启动三个Node.js实例
node app.js --port 3000 &
node app.js --port 3001 &
node app.js --port 3002 &

Nginx 配置:

http {
    upstream nodejs_app {
        server localhost:3000;
        server localhost:3001;
        server localhost:3002;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://nodejs_app;
        }
    }
}

数据共享问题

每个Node.js实例都是独立的进程,因此它们之间无法直接共享内存中的数据。为了实现数据共享,可以使用多种方法:

  1. 数据库:使用MySQL、MongoDB等数据库存储共享数据。
  2. Redis:使用Redis作为缓存或数据存储,提供快速的数据读写能力。
  3. 消息队列:使用RabbitMQ、Kafka等消息队列进行进程间通信。

示例:使用Redis进行数据共享

const redis = require('redis');
const client = redis.createClient();

client.set('key', 'value', (err, reply) => {
    console.log(reply); // OK
});

client.get('key', (err, reply) => {
    console.log(reply); // value
});

使用子进程

另一种方法是使用Node.js的child_process模块创建子进程。这些子进程可以共享同一个端口,并且可以通过IPC(进程间通信)机制交换数据。

示例:使用子进程

const { fork } = require('child_process');

// 创建两个子进程
const childA = fork('childA.js');
const childB = fork('childB.js');

// 子进程之间通过IPC通信
childA.send({ type: 'data', data: [1, 2, 3] });
childB.on('message', (msg) => {
    console.log(msg.data); // [1, 2, 3]
});

子进程之间的数据共享

假设你有一个数组在NodeA中,你可以通过IPC将这个数组发送给其他子进程。

// NodeA.js
process.send({ type: 'array', data: [1, 2, 3] });

// 其他子进程接收数据
process.on('message', (msg) => {
    if (msg.type === 'array') {
        console.log(msg.data); // [1, 2, 3]
    }
});

客户端访问

当客户端访问端口3000时,Nginx会根据其配置将请求转发到不同的Node.js实例。例如,Nginx可能会使用轮询算法将请求均匀地分配给NodeA, NodeB, 和 NodeC

总结

  • 使用Nginx或类似工具进行负载均衡,可以将请求分发到多个Node.js实例。
  • 通过数据库、Redis或消息队列等方式实现数据共享。
  • 使用子进程并通过IPC机制交换数据,实现更复杂的进程间通信。

希望这些信息能帮助你更好地理解和解决你的疑惑。


尽量不要使用进程间共享,如有需要,请使用memcache或者,redis等共享状态

不能同一个端口把。。。会报异常把

那么pm2 的多核心是什么意思,我可以使用pm2 start app.js -i max,他会出现多个进程

那么我是不是需要比如一台四核的机器,那么开4个instance,然后把需要的数据存进redis,然后通过redis来实现共享呢?

官方的标准cluster模块更优

Node.js 在默认情况下确实会以单线程运行,但可以通过多种方式实现多核 CPU 的利用。以下是几种常见的方法来解决你的问题:

使用 cluster 模块

cluster 模块允许你在同一端口上创建多个工作进程,每个进程都在不同的核心上运行。这样可以充分利用多核 CPU。

示例代码:

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

if (cluster.isMaster) {
    console.log(`主进程 ${process.pid} 正在运行`);

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

    cluster.on('exit', (worker, code, signal) => {
        console.log(`工作进程 ${worker.process.pid} 已退出`);
    });
} else {
    // 这是工作进程的代码
    http.createServer((req, res) => {
        res.writeHead(200);
        res.end('Hello World\n');
    }).listen(3000);

    console.log(`工作进程 ${process.pid} 已启动`);
}

数据共享

使用 cluster 模块时,工作进程之间不会自动共享内存。如果你需要在工作进程中共享数据,可以考虑以下方法:

  1. 数据库:将数据存储在数据库中,所有工作进程都可以通过数据库进行读写操作。
  2. Redis:使用 Redis 等内存存储系统作为缓存,所有工作进程可以读写相同的数据。
  3. IPC(进程间通信):使用 process.send()process.on('message') 方法在工作进程中传递消息。

示例代码(使用 IPC):

if (cluster.isMaster) {
    const worker = cluster.fork();
    worker.send({ type: 'data', data: [1, 2, 3] });

    worker.on('message', (msg) => {
        console.log(`收到消息:${msg.data}`);
    });
} else {
    process.on('message', (msg) => {
        if (msg.type === 'data') {
            console.log(`接收到的数据:${msg.data}`);
            process.send({ type: 'ack', data: msg.data });
        }
    });
}

客户端请求分配

当客户端访问端口 3000 时,Nginx 通常会负责负载均衡,将请求分发给不同的工作进程。你可以配置 Nginx 来实现这一点。

示例 Nginx 配置:

http {
    upstream node_cluster {
        server 127.0.0.1:3000;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://node_cluster;
        }
    }
}

这样,Nginx 会将请求均匀地分发到各个工作进程上。

希望这些信息对你有所帮助!

回到顶部