Nodejs 求指导:根据url路由到不同的子进程进行处理

Nodejs 求指导:根据url路由到不同的子进程进行处理

我希望能用一个master生成若干childprocess,由master负责接收request,然后根据url路由到不同的childprocess进行处理(这是由于数据同步要求只能分派到固定的一个process进行处理),这显然无法用cluster解决。当然也可以让子进程侦听不同端口,由master转发request,但这样要引入额外间接层和开销。 是否有高手可以提供指导,不胜感激!

7 回复

当然可以!你希望使用 Node.js 创建一个主进程 (master) 和多个子进程 (childprocess),并且根据请求的 URL 路由到不同的子进程进行处理。以下是一个简单的实现方案,包括基本的代码示例和解释。

实现思路

  1. 主进程 (master): 接收 HTTP 请求并根据 URL 将请求路由到相应的子进程。
  2. 子进程 (childprocess): 处理从主进程接收到的请求,并返回响应。

示例代码

主进程 (master)

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

// 创建子进程
const child1 = fork('./child1.js');
const child2 = fork('./child2.js');

// 存储子进程的通信管道
const childProcesses = {
    '/path1': child1,
    '/path2': child2
};

const server = http.createServer((req, res) => {
    const url = req.url;

    // 根据URL选择对应的子进程
    if (childProcesses[url]) {
        childProcesses[url].send({ type: 'request', data: { url, body: '' } });
        
        // 监听子进程的消息
        childProcesses[url].on('message', (msg) => {
            res.writeHead(200, { 'Content-Type': 'text/plain' });
            res.end(msg.data);
        });
    } else {
        res.writeHead(404, { 'Content-Type': 'text/plain' });
        res.end('Not Found');
    }
});

server.listen(3000, () => {
    console.log('Server is running on port 3000');
});

子进程 (child1.jschild2.js)

process.on('message', (msg) => {
    if (msg.type === 'request') {
        // 这里模拟处理请求
        const response = `Processed by ${process.pid} for path ${msg.data.url}`;
        process.send({ type: 'response', data: response });
    }
});

解释

  1. 主进程 创建了两个子进程 (child1.jschild2.js),并将它们映射到特定的 URL 路径。
  2. 当主进程接收到请求时,它会根据请求的 URL 选择相应的子进程,并通过进程间的通信 (IPC) 发送请求数据。
  3. 子进程接收到请求后,模拟处理请求,并将结果发送回主进程。
  4. 主进程接收到子进程的结果后,将其作为 HTTP 响应返回给客户端。

这种方法避免了为每个子进程创建独立的 HTTP 端口,从而减少了额外的复杂性和开销。


手一滑不知为何发了3遍,囧

你的 childprocess 要和 master 是不同的 thread 吗?

是的。事实上,每个childprocess对应我一个独立的数据库,独立进程对于架构的安全和灵活还是很重要的。

这本质上就是所谓的IPC问题(inter-process communication),成熟的解决方案就那几种,具体到nodejs平台上的选择貌似就3种,pipe/socket/unix domain socket,无论怎么折腾,若想把req,res直接传递到子进程,那是门都没有。就楼主的情况,选择unix domain socket吧,它的开销远低于连接数据库的开销,在考虑转发对性能的影响前,先考虑下改善数据库的访问速度吧。

可能有人不知道domain socket是什么玩意,其实就是server监听unix的某个path,与传统的socket区别就是domain socket没有额外的网络数据包开销,直接是内存数据的复制。

http.createServer(function(req,res){
   //............
}).listen('/var/tmp/test.sock'); 

var opts={ socketPath:’/var/tmp/test.sock’ // more options… } var req=http.request(opts)

首先感谢shiedman的指导

目前看来传递socket应该是可取的方向,不过考虑到增加了socket路由等一系列的复杂性,所以我打算退而求其次,多开几个http server和端口,利用反向代理来解决问题了

在Node.js中实现根据URL路由到不同的子进程进行处理的需求时,可以通过child_process模块来创建子进程,并通过IPC(进程间通信)机制来进行消息传递。下面是一个简单的示例,展示了如何根据请求的URL将任务分配给不同的子进程。

示例代码

Master进程 (server.js)

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

// 创建子进程
const processA = fork('./workerA.js');
const processB = fork('./workerB.js');

const server = http.createServer((req, res) => {
    const url = req.url;

    if (url.startsWith('/processA')) {
        processA.send({ type: 'task', data: url }, req, [req.socket]);
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end('Request sent to Process A');
    } else if (url.startsWith('/processB')) {
        processB.send({ type: 'task', data: url }, req, [req.socket]);
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end('Request sent to Process B');
    } else {
        res.writeHead(404, { 'Content-Type': 'text/plain' });
        res.end('Not Found');
    }
});

server.listen(3000, () => {
    console.log('Server is running on port 3000');
});

Worker进程 (workerA.js 和 workerB.js)

workerA.js为例:

process.on('message', (msg, socket) => {
    if (msg.type === 'task') {
        // 处理请求
        console.log(`Worker A received task: ${msg.data}`);
        socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>Process A Response</h1>');
        socket.end();
    }
});

workerB.js的代码与workerA.js类似,只需修改响应内容。

解释

  • Master进程:负责启动HTTP服务器,并根据请求的URL将任务发送给相应的子进程。使用process.send方法向子进程发送消息,并通过第三个参数传递socket对象。
  • 子进程:监听来自master的消息,并根据接收到的任务类型执行相应的操作。使用process.on('message')监听消息,并通过socket对象直接向客户端返回响应。

这种方式避免了为每个子进程单独开启端口的需求,减少了额外的间接层和开销。

回到顶部