Source: http://blog.fens.me/nodejs-core-cluster/
The zero-based NODEJS series article will show you how to benefit JavaScript as a server-side script through NODEJS Framework web development. The NODEJS framework is a V8-based engine and is the fastest JavaScript engine available today. The Chrome browser is based on V8, and opening 20-30 pages is a smooth one. The NODEJS Standard Web Development Framework Express helps us quickly build web sites that are more efficient than PHP and have a lower learning curve. Very suitable for small websites, personalization sites, our own Geek website!!
About the author
- Zhang Dan (Conan), programmer Java,r,php,javascript
- Weibo: @Conan_Z
- Blog:http://blog.fens.me
- Email: [Email protected]
Reprint please specify the source:
http://blog.fens.me/nodejs-core-cluster/
Objective
As you know, Nodejs is a single-process single-threaded server engine that can only be computed with a single CPU, no matter how powerful the hardware. So, someone developed a third-party cluster that allows node to take advantage of multi-core CPUs for parallelism.
With the development of Nodejs, let Nodejs on the production environment, it is necessary to support multi-process multi-core processing! In the V0.6.0 version, the Nodejs has built-in cluster features. Since then, Nodejs finally can be used as an independent application development solutions, reflected in the eyes of everyone.
Directory
- Cluster introduction
- Simple use of cluster
- How the cluster works
- Cluster's API
- Communication of Master and worker
- Load balancing (load Balance)-win7 failed with cluster
- Load balancing with cluster (load Balance)-ubuntu success
- Test of cluster load balancing strategy
1. Cluster introduction
The cluster is a NODEJS built-in module for Nodejs multicore processing. The cluster module can help us simplify the development of multi-process parallelization programs and easily build a cluster for load balancing.
2. Simple use of cluster
My system environment
- Win7 64bit
- nodejs:v0.10.5
- npm:1.2.19
In the win environment, we provide Web services through cluster, which initiates multi-core node.
New Project Catalog:
~ D:\workspace\javascript>mkdir nodejs-cluster && cd nodejs-cluster
New file: App.js
~ vi app.jsvar cluster = require(‘cluster‘);var http = require(‘http‘);var numCPUs = require(‘os‘).cpus().length;if (cluster.isMaster) { console.log("master start..."); // Fork workers. for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on(‘listening‘,function(worker,address){ console.log(‘listening: worker ‘ + worker.process.pid +‘, Address: ‘+address.address+":"+address.port); }); cluster.on(‘exit‘, function(worker, code, signal) { console.log(‘worker ‘ + worker.process.pid + ‘ died‘); });} else { http.createServer(function(req, res) { res.writeHead(200); res.end("hello world\n"); }).listen(0);}
Start the node program in the console
~ D:\workspace\javascript\nodejs-cluster>node app.jsmaster start...listening: worker 2368, Address: 0.0.0.0:57132listening: worker 1880, Address: 0.0.0.0:57132listening: worker 1384, Address: 0.0.0.0:57132listening: worker 1652, Address: 0.0.0.0:57132
Master is the master node, and the worker is the running node. The worker is then started based on the number of CPUs. I am a dual-core dual-channel CPU, so I was detected as a 4-core and started 4 worker.
3. How the cluster works
Each worker process implements communication with the master process by using the Child_process.fork () function, based on the IPC (inter-process communication, interprocess communication).
When the worker uses Server.listen (... ) function, the parameter sequence is passed to the master process. If the master process already matches workers, the handle is passed to the worker. If Master does not match a good worker, a worker is created, and then passed and the handle is passed to the worker.
In the boundary condition, there are 3 interesting behaviors:
Note: Below Server.listen (), is on the underlying "HTTP." Server-->net. The call to the Server class.
- 1. Server.listen ({fd:7}): In the master and worker communication process, by passing the file, master listens for "file description is 7" Instead of passing a "file description of 7" reference.
- 2. Server.listen (handle): Master and Worker communication process, communication via handle function without process contact
- 3. Server.listen (0): In the master and Worker communication process, the worker in the cluster opens a random port to be shared, through the socket communication, as in the above example 57132
The load balancing of the operating system is very efficient when multiple processes are in the same resource as the accept (). node. js does not have routing logic and there is no shared state between workers. Therefore, the program should be designed to be simple, such as memory-based session.
Because workers are run on their own, they can be removed or restarted independently, depending on the needs of the program, and workers do not affect each other. As long as there is workers alive, Master will continue to receive the connection. Node does not automatically maintain the number of workers. We can build our own pool of connections.
4. Cluster's API
Website address: Http://nodejs.org/api/cluster.html#cluster_cluster
Cluster object
Various properties and functions of the cluster
- Cluster.setttings: Configuring cluster Parameter objects
- Cluster.ismaster: Judging is not the master node
- Cluster.isworker: Determine if the worker node is not
- Event: ' Fork ': Listener Creation worker process event
- Event: ' Online ': Listener worker Creation Success Event
- Event: ' Listening ': Listener worker to master status event
- Event: ' Disconnect ': Monitoring worker disconnection Event
- Event: ' Exit ': Listener worker Exit event
- Event: ' Setup ': Monitoring Setupmaster events
- Cluster.setupmaster ([Settings]): Set cluster parameters
- Cluster.fork ([env]): Create worker process
- Cluster.disconnect ([callback]): Close the Worket process
- Cluster.worker: Gets the current worker object
- Cluster.workers: Get all the surviving worker objects in the cluster
Worker Object
Various properties and functions of the worker: can be obtained by cluster.workers, Cluster.worket.
- Worker.id: Process ID Number
- Worker.process:ChildProcess Object
- Worker.suicide: After disconnect (), determine whether the worker committed suicide
- Worker.send (message, [Sendhandle]): Master sends a message to the worker. Note: The worker sends a message to the Send master using process.send (message)
- Worker.kill ([signal= ' SIGTERM ']): kills the specified worker, alias Destory ()
- Worker.disconnect (): Disconnect worker, let worker commit suicide
- Event: ' message ': Listen for the message event of master and worker
- Event: ' Online ': Listen for the specified worker creation success event
- Event: ' Listening ': Monitor master to worker status event
- Event: ' Disconnect ': Monitoring worker disconnection Event
- Event: ' Exit ': Listener worker Exit event
5. Master and Worker Communication
Implement the cluster API to allow master and worker to communicate with each other.
New file: Cluster.js
~ VI cluster.jsvar cluster = require (' cluster '); var http = require (' http '); var Numcpus = require (' OS '). CPUs (). Length;if (c Luster.ismaster) {console.log (' [Master] ' + "Start master ..."); for (var i = 0; i < Numcpus; i++) {var wk = cluster.fork (); Wk.send (' [Master] ' + ' Hi worker ' + wk.id); } cluster.on (' fork ', function (worker) {console.log (' [Master] ' + ' fork:worker ' + worker.id); }); Cluster.on (' online ', function (worker) {console.log (' [Master] ' + ' online:worker ' + worker.id); }); Cluster.on (' Listening ', function (worker, address) {Console.log (' [Master] ' + ' listening:worker ' + worker.id + ', PID: ' + Worker.process.pid + ', Address: ' + address.address + ': "+ address.port); }); Cluster.on (' Disconnect ', function (worker) {console.log (' [Master] ' + ' disconnect:worker ' + worker.id); }); Cluster.on (' Exit ', function (worker, code, signal) {console.log (' [Master] ' + ' exit worker ' + Worker.id + ' died '); }); function Eachworker (callback) {for (var ID in cluster.workers) {callback (Cluster.workers[id]); }} setTimeout (function () {Eachworker (function (worker) {worker.send (' [Master] ' + ' send Messa GE to worker ' + worker.id); }); }, 3000); Object.keys (cluster.workers). ForEach (function (ID) {cluster.workers[id].on (' message ', function (msg) {con Sole.log (' [Master] ' + ' message ' + msg); }); });} else if (cluster.isworker) {console.log (' [worker] ' + "start worker ..." + cluster.worker.id); Process.on (' message ', function (msg) {Console.log (' [worker] ' +msg); Process.send (' [worker] worker ' +cluster.worker.id+ ' received! '); }); Http.createserver (function (req, res) {Res.writehead ($, {"Content-type": "Text/html"}); Res.end (' worker ' +cluster.worker.id+ ', PID: ' +process.pid '); }). Listen (3000);}
Console log:
~ D:\workspace\javascript\nodejs-cluster>node Cluster.js[master] Start master ... [worker] Start worker ... 1[worker] [master] Hi Worker1[worker] Start worker ... 2[worker] [master] Hi Worker2[master] fork:worker1[master] fork:worker2[master] Fork:worker3[master] Fork:worker4[mas TER] Online:worker1[master] online:worker2[master] message [worker] Worker1 received! [Master] message [worker] Worker2 received! [Master] listening:worker1,pid:6068, Address:0.0.0.0:3000[master] listening:worker2,pid:1408, Address:0.0.0.0:3000 [Master] online:worker3[worker] Start worker ... 3[worker] [master] Hi worker3[master] message [worker] Worker3 received! [Master] listening:worker3,pid:3428, Address:0.0.0.0:3000[master] online:worker4[worker] Start worker ... 4[worker] [master] Hi worker4[master] message [worker] Worker4 received! [Master] listening:worker4,pid:6872, Address:0.0.0.0:3000[worker] [master] Send message to Worker1[worker] [master] Send message to Worker2[worker] [master] Send Messageto Worker3[worker] [master] Send message to Worker4[master] message [worker] Worker1 received! [Master] message [worker] Worker2 received! [Master] message [worker] Worker3 received! [Master] message [worker] Worker4 received!
6. Load balancing with cluster (load Balance)--Win7 failure
New file: Server.js
~ vi server.jsvar cluster = require(‘cluster‘);var http = require(‘http‘);var numCPUs = require(‘os‘).cpus().length;if (cluster.isMaster) { console.log(‘[master] ‘ + "start master..."); for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on(‘listening‘, function (worker, address) { console.log(‘[master] ‘ + ‘listening: worker‘ + worker.id + ‘,pid:‘ + worker.process.pid + ‘, Address:‘ + address.address + ":" + address.port); });} else if (cluster.isWorker) { console.log(‘[worker] ‘ + "start worker ..." + cluster.worker.id); http.createServer(function (req, res) { console.log(‘worker‘+cluster.worker.id); res.end(‘worker‘+cluster.worker.id+‘,PID:‘+process.pid); }).listen(3000);}
Start the server:
~ D:\workspace\javascript\nodejs-cluster>node server.js[master] start master...[worker] start worker ...1[worker] start worker ...2[master] listening: worker1,pid:1536, Address:0.0.0.0:3000[master] listening: worker2,pid:5920, Address:0.0.0.0:3000[worker] start worker ...3[master] listening: worker3,pid:7156, Address:0.0.0.0:3000[worker] start worker ...4[master] listening: worker4,pid:2868, Address:0.0.0.0:3000worker4worker4worker4worker4worker4worker4worker4worker4
Use the Curl tool to access
C:\Users\Administrator>curl localhost:3000worker4,PID:2868C:\Users\Administrator>curl localhost:3000worker4,PID:2868C:\Users\Administrator>curl localhost:3000worker4,PID:2868C:\Users\Administrator>curl localhost:3000worker4,PID:2868C:\Users\Administrator>curl localhost:3000worker4,PID:2868C:\Users\Administrator>curl localhost:3000worker4,PID:2868C:\Users\Administrator>curl localhost:3000worker4,PID:2868C:\Users\Administrator>curl localhost:3000worker4,PID:2868
We found cluster in Win's bug, only used to worker4. Switch decisively to Linux testing.
7. Load balancing with cluster (load Balance)--Ubuntu success
Linux's system environment
- Linux:ubuntu 12.04.2 64bit Server
- node:v0.11.2
- npm:1.2.21
Build project: Not much explanation
~ cd :/home/conan/nodejs/~ mkdir nodejs-cluster && cd nodejs-cluster~ vi server.jsvar cluster = require(‘cluster‘);var http = require(‘http‘);var numCPUs = require(‘os‘).cpus().length;if (cluster.isMaster) { console.log(‘[master] ‘ + "start master..."); for (var i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on(‘listening‘, function (worker, address) { console.log(‘[master] ‘ + ‘listening: worker‘ + worker.id + ‘,pid:‘ + worker.process.pid + ‘, Address:‘ + address.address + ":" + address.port); });} else if (cluster.isWorker) { console.log(‘[worker] ‘ + "start worker ..." + cluster.worker.id); http.createServer(function (req, res) { console.log(‘worker‘+cluster.worker.id); res.end(‘worker‘+cluster.worker.id+‘,PID:‘+process.pid); }).listen(3000);}
Start the server
[email protected]:~/nodejs/nodejs-cluster$ node server.js[master] start master...[worker] start worker ...1[master] listening: worker1,pid:2925, Address:0.0.0.0:3000[worker] start worker ...3[master] listening: worker3,pid:2931, Address:0.0.0.0:3000[worker] start worker ...4[master] listening: worker4,pid:2932, Address:0.0.0.0:3000[worker] start worker ...2[master] listening: worker2,pid:2930, Address:0.0.0.0:3000worker4worker2worker1worker3worker4worker2worker1
Use the Curl tool to access
C:\Users\Administrator>curl 192.168.1.20:3000worker4,PID:2932C:\Users\Administrator>curl 192.168.1.20:3000worker2,PID:2930C:\Users\Administrator>curl 192.168.1.20:3000worker1,PID:2925C:\Users\Administrator>curl 192.168.1.20:3000worker3,PID:2931C:\Users\Administrator>curl 192.168.1.20:3000worker4,PID:2932C:\Users\Administrator>curl 192.168.1.20:3000worker2,PID:2930C:\Users\Administrator>curl 192.168.1.20:3000worker1,PID:2925
In the Linux environment, cluster is running correctly!!!
8. Test of cluster load balancing strategy
We are under Linux, finished testing, tested software: Siege
Installing siege
~ sudo apt-get install siege
Start node cluster
~ node server.js > server.log
Run the Siege startup command with 50 concurrent requests per second.
~ sudo siege-c-http://localhost:3000HTTP/1.1-0.00 secs:16 Bytes ==>/http/1.1-0.00 Secs:16 Bytes ==>/http/1.1 0.00 Secs:16 Bytes ==>/http/1.1 $0.01 secs:16 bytes ==>/http/1.1 200 0.00 Secs:16 Bytes ==>/http/1.1 $0.00 Secs:16 bytes ==>/http/1.1 $0.00 Secs:16 Byte S ==>/http/1.1 0.01 secs:16 bytes ==>/http/1.1 $0.00 secs:16 bytes ==>/http/1.1 200 0 . secs:16 bytes ==>/http/1.1, 0.00 secs:16 bytes ==>/http/1.1, 0.02 secs:16 bytes = = >/http/1.1 0.00 secs:16 bytes ==>/http/1.1 $0.02 secs:16 bytes ==>/http/1.1 200 0.01 Secs:16 bytes ==>/http/1.1, 0.01 secs:16 bytes ==>/.....^clifting the server siege ... done. transactions:3760 hitsavailability: 100.00%elapsed time:39.66 secsdata transferred:0.06 mbresponse time:0.01 Secstran Saction rate:94.81 trans/secthroughput:0.00 mb/secconcurrency:1.24s Uccessful transactions:3760failed transactions:0longest transaction:0.20shortest Transa Ction:0.00file:/var/siege.logyou can disable this annoying message by editingthe. siegerc file in your home di Rectory; changethe directive ' show-logfile ' to false.
We counted the results, executed 3,760 requests, consumed 39.66 seconds, and processed 94.81 requests per second.
View Server.log file,
~ ls -ltotal 64-rw-rw-r-- 1 conan conan 756 9月 28 15:48 server.js-rw-rw-r-- 1 conan conan 50313 9月 28 16:26 server.log~ tail server.logworker4worker1worker2worker4worker1worker2worker4worker3worker2worker1
Finally, analyze with the R language: Server.log
~ R > df<-read.table(file="server.log",skip=9,header=FALSE)> summary(df) V1 worker1:1559 worker2:1579 worker3:1570 worker4:1535
We see that the request is allocated equal to the amount of worker data. Therefore, the cluster load balancing strategy should be randomly allocated.
Well, we've learned a very useful skill! Using cluster can build multi-core applications, take full advantage of multi-CPU industry performance Bar!!
Interpreting the Nodejs multi-core processing module cluster