Nodejs play process

First of all, we should know that node is executed by single thread, but today's computer has developed to multi-core CPU. Therefore, it has become an important problem to solve the problem of node using multi-core CPU server.

I Multi process architecture

Analysis: in master JS folder, through child_process to copy sub processes, and os to access the number of CPU s to control how many sub processes are copied. At the same time, the monitoring of 3000 ~ 4000 random ports is enabled in the sub processes.

// master.js

let fork = require('child_process').fork;
let cpus = require('os').cpus();
for(let i = 0; i< cpus.length; i ++){
    fork('./worker.js');
}



// worker.js
let http = require('http');
http.createServer((req, res) => {
    res.writeHead(200,{'Content-Type':'text/plain'});
    res.end('hello word');
}).listen(Math.round((3 + Math.random()) * 1000 ) , '127.0.0.1');

1. Create sub process

spawnStart the subprocess to execute the command
execStart a child process to execute commands, but it has a callback function to know the status of the child process
execFileStart a sub process to execute the executable
forkSimilar to spawn, the difference is that it only needs to specify the js file module to be executed to create the Node sub process

Please check the official documents for details: child_process creation

2. Inter process communication

Analysis: the parent-child process listens for incoming messages through on and send s messages. The communication between them will create an IPC channel. Only through this channel can the message transmission of the parent-child process be realized.

// master.js main process
let cp = require('child_process');
let worker = cp.fork('./worker.js');


// Used to listen for information from child processes
worker.on('message', ( data ) =>{
    console.log('Received message from child process: ', data);
})

// Used to send information to child processes
worker.send('Hello, subprocess ');


// worker.js work process
// Send information to the main process in 3 seconds
setTimeout(()=>{
    process.send({name: 'Stone Mountain'});
},3000)


// Used to listen for messages from the parent process
process.on('message', (data) => {
    console.log('I got it.', data);
})
  • Principle of interprocess communication

The full name of IPC is inter process communication, that is, inter process communication. The purpose of inter process communication is to enable different processes to access resources and coordinate work with each other.

Before creating a child process, the parent process will first create an IPC channel and listen to it, and then really create a child process, and tell the child process the file descriptor of this IPC channel through the environment variable( File descriptor interpretation ). During the startup process, the child process connects the existing IPC channel according to the file descriptor, so as to complete the connection between the parent and child processes. Its behavior is similar to that of socket, but it omits the network layer and is completed directly in the system kernel, which is more efficient.

3. Handle transfer

First, we introduce a concept, handle. What is handle? A handle is a reference used to identify a resource. It contains a file descriptor pointing to an object. For example, handles can be used to identify a server socket object, a client socket object, a UDP socket, and a pipe.

Let's imagine such a scenario. For example, an interface is accessed by a large number of users at the same time. At this time, the node of a single thread is more difficult. Although we can make use of the characteristics of multiple processes, how to make multiple processes listen to the same port at the same time has become a difficult problem, which requires the so-called handle transfer function.

Analysis: the main process passes the} server to the sub process, starts listening and then closes the server, so that the sub process can directly listen to the port. Each request is randomly responded by a sub process, and the response between them is preemptive.

// parent.js start the main process
let cp = require('child_process');
let cpus = require('os').cpus


let child2 = cp.fork('child2.js');
let child1 = cp.fork('child1.js');
console.log(cpus)

let server = require('net').createServer();

server.on('connection', socket => {
    socket.end('handled by parent');
})

server.listen(1337, () => {
    child1.send('server1', server);
    child2.send('server2', server);
    
    server.close();
})

// child1 process
let http = require('http');
let server = http.createServer((req, res ) => {
    if(req.url === '/') {
        res.writeHead(200, {'Content-Type':'text/plain'});
        res.end('handled by child1, pid is' + process.pid + '\n');
    }

})
process.on('message', ( m, tcp ) => {
    if( m === 'server1') {
        tcp.on('connection', socket => {
            server.emit('connection', socket);
        })
    }
})

// child2 process
let http = require('http');
let server = http.createServer((req, res ) => {
    if(req.url === '/index'){
        res.writeHead(200, {'Content-Type':'text/plain'});
        res.end('handled by child2, pid is' + process.pid + '\n');
    }


})

process.on('message', ( m, tcp ) => {
    console.log(22222)
    if( m === 'server2') {
        tcp.on('connection', socket => {
            server.emit('connection', socket);
        })
    }
})

II The road of cluster stability

By making full use of the resources of multi-core CPU, we can meet a large number of client requests, but we still need to consider many problems, such as performance, multiple process survival status, process restart and so on.

1. Process events

Please refer to the official documents for details: Process events

errorTriggered when a child process cannot be copied, created, killed, or sent
exitThis event is triggered when the child process exits
close        Triggered when the child process's standard I / O stream terminates
disconnectTriggers when calling the disconnect() method in the parent or subprocess, and closes the IPC channel.

2. Automatic restart

Analysis: obtain the number of computer cpu cores through os files to create the most working processes, and listen to the emit event of the working process. Once a process exits, start a new process immediately to ensure that there are always processes serving users in the whole cluster.

let fork = require('child_process').fork;
let cpus = require('os').cpus();

let server = require('net').createServer();
server.listen(1337);

let workers = {};

let createWorker = function (i) {
    let worker = fork(__dirname + `/worker${i}.js`);
    // Restart the new process on exit
    worker.on('exit', () => {
        console.log('Worker' + worker.pid + 'exited');
        delete workers[worker.pid];
        createWorker();
    })

// Handle forwarding
worker.send('server' + i, server);

console.log('Create worker.pid = ' + worker.pid);

};

for(let i = 0; i< cpus.length; i++) {
    createWorker(i);
}

// Let all working processes exit when the process exits
process.on('exit', ()=>{
    for(let pid in workers){
        workers[pid].kill();
    }
})
  • Suicide signal

Analysis: the process listens for uncapped exceptions. In case of uncapped exceptions, it sends a suicide signal to the main process. After receiving the signal, the main process knows that a process stops working, and then restarts a new process.

// Suicide signal
process.on('uncaughtException', () => {
    process.send({act: 'suicide'});
    // Stop receiving new signals
    worker.close(()=>{
        // Exit the process after all existing connections are disconnected
        process.exit(1);
    })
});

3. Load balancing

Listening to the same port between multiple processes enables user requests to be distributed to multiple processes for processing, which enables CPU resources to be called completely. To prevent a process from working all the time and some processes from stalling, the default mechanism of Node is to adopt the preemptive strategy of the operating system. This strategy may cause load imbalance. Therefore, Node v0 A new strategy, round robin, is proposed. Its working mode is that the main process accepts the connection and sends it to the working process in turn. The distribution strategy is to select the i = (i + 1) mod n process to send the connection in N working processes each time.

4. Status sharing

We know that too much data should not be placed in the Node process, because it will increase the burden of garbage collection and affect the performance. At the same time, Node does not allow data sharing among multiple processes. However, it is often inevitable in actual business, so we need to use a scheme and mechanism to realize data sharing among multiple processes.

  • Third party data storage: in database, disk file and cache service Redis
  • Timed polling: each sub process polls the third party regularly
  • Active notification: when the data changes, the main process notifies each sub process in turn

III Cluster module

Cluster is a mature module for processing multi-core CPU s in Node. In v0 Before 8, process was used_ Child. After that, using cluster can solve its problem well. It provides a relatively perfect API to deal with the robustness of the process.

Analysis: through cluster Ismaster determines whether it is the main process, and then creates a working process or a listener.

let cluster = require('cluster');
let http = require('http');
const { off } = require('process');
let numCPUs = require('os').cpus().length;

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

    cluster.on('exit', (worker, code, signal)=>{
        console.log('worker' + worker.process.pid + 'died');
    });
}else{
    http.createServer((req, res)=>{
        res.writeHead(200);
        res.end('hellow world'+ process.pid + '\n');
    }).listen(8000)
}
// cluster.setupMaster({
//     exec: 'worker.js'
// })


IV summary

The power of the group is powerful. Through the master-slave mode, the quality of the application has been improved to a higher level. In the design, each sub process should only do one thing and do one thing well. They are connected through inter process technology to combine simple into powerful.

Keywords: node.js Back-end server multiple processes Network Protocol

Added by Rianna on Fri, 04 Feb 2022 05:36:00 +0200