1. node.js 單線程的特點(diǎn)
node.js 以異步非阻塞單線程街氢,作為其執(zhí)行速度的保障。什么是非阻塞單線程睦袖?
舉一個現(xiàn)實(shí)生活中的例子珊肃,我去巢大食堂打飯,我選擇了A套餐,然后工作人員區(qū)為我配餐伦乔,我就在旁邊等著直到阿姨叫號然后我取餐厉亏。這個過程是同步。
如果工作人員在為我配餐的同時评矩,仍然可以接受排在我后面的同學(xué)的點(diǎn)餐叶堆,這樣餐廳并沒有因?yàn)槲以诘却鼳套餐而停止阱飘。這個過程是非阻塞斥杜。
如果我在阿姨為我配餐的同時,我去旁邊小超市買了杯冷飲沥匈,等阿姨叫號時我再去取餐蔗喂。這個過程就是異步非阻塞,同時阿姨叫號我去取餐的行為叫做回調(diào)高帖。
- 高性能(不用考慮多線程間來回調(diào)用引起性能的損耗)
- 線程安全(不用擔(dān)心同意變量會被多線程進(jìn)行讀寫而造成程序的崩潰)
-
底層多線程
說node.js 是單線程其實(shí)也是不全面的缰儿,node.js 底層庫會使用libuv調(diào)用多線程來處理I/O 操作。這就像食堂只有一個窗口散址,只能有按順序一個個的接收點(diǎn)餐乖阵,但是后廚配菜的員工卻有很多,他們各司其職保證出餐的速度预麸。
如果服務(wù)器是多核且有充足的物理資源瞪浸,如何充分發(fā)揮這些物理資源達(dá)到性能最大化。既食堂后廚有很多大師傅吏祸,一個窗口售賣的速度太慢对蒲,許多大師傅都是空閑的窗臺。邪惡的資本家你們懂的贡翘?
2.如何通過多線程提高node.js 的性能
- cluster: 為了利用多核系統(tǒng)蹈矮,用戶有時會想啟動一個 Node.js 進(jìn)程的集群去處理負(fù)載。
const Koa = require('Koa');
const koaRouter = require('koa-router');
const app = new Koa();
const router = new koaRouter();
function fibo(n) {
return n > 1 ? fibo(n - 1) + fibo(n-2) : 1
}
app.use(router['routes']());
router.get('/', function(ctx, next) {
var result = fibo(35);
ctx.body = `${result}`;
});
if (!module.parent) {
app.listen(8080);
console.log(`Server was start.`);
}
通過ab 壓力測試命令:
ab -c 20 -n 100 http://localhost:8080/
沒有經(jīng)過cluster 集群優(yōu)化:
Server Software:
Server Hostname: localhost
Server Port: 8080
Document Path: /
Document Length: 8 bytes
Concurrency Level: 20
Time taken for tests: 13.569 seconds
Complete requests: 100
Failed requests: 0
Total transferred: 14300 bytes
HTML transferred: 800 bytes
Requests per second: 7.37 [#/sec] (mean)
Time per request: 2713.723 [ms] (mean)
Time per request: 135.686 [ms] (mean, across all concurrent requests)
Transfer rate: 1.03 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.2 0 1
Processing: 155 2465 622.9 2738 2762
Waiting: 153 2465 623.0 2737 2762
Total: 155 2465 622.8 2738 2762
Percentage of the requests served within a certain time (ms)
50% 2738
66% 2743
75% 2746
80% 2747
90% 2753
95% 2757
98% 2761
99% 2762
100% 2762 (longest request)
通過cluster 集群優(yōu)化后:
const Koa = require('Koa');
const koaRouter = require('koa-router');
const numCpus = require('os').cpus().length;
const cluster = require('cluster');
const app = new Koa();
const router = new koaRouter();
if (cluster.isMaster) {
console.log(`${numCpus}`);
for (var index = 0; index < numCpus; index++) {
cluster.fork();
}
} else {
app.use(router['routes']());
router.get('/', function(ctx, next) {
var result = fibo(35);
ctx.body = `${result}`;
});
if (!module.parent) {
app.listen(8080);
console.log(`Server was start.`);
}
}
function fibo(n) {
return n > 1 ? fibo(n - 1) + fibo(n-2) : 1
}
通過ab 壓力測試命令:
ab -c 20 -n 100 http://localhost:8080/
Server Software:
Server Hostname: localhost
Server Port: 8080
Document Path: /
Document Length: 8 bytes
Concurrency Level: 20
Time taken for tests: 6.513 seconds
Complete requests: 100
Failed requests: 0
Total transferred: 14300 bytes
HTML transferred: 800 bytes
Requests per second: 15.35 [#/sec] (mean)
Time per request: 1302.524 [ms] (mean)
Time per request: 65.126 [ms] (mean, across all concurrent requests)
Transfer rate: 2.14 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.5 0 2
Processing: 279 1198 258.7 1294 1335
Waiting: 279 1198 258.7 1294 1335
Total: 281 1198 258.3 1295 1335
Percentage of the requests served within a certain time (ms)
50% 1295
66% 1301
75% 1303
80% 1308
90% 1322
95% 1328
98% 1333
99% 1335
100% 1335 (longest request)
對比兩次的測試結(jié)果:
優(yōu)化后鸣驱,
Requests per second (每秒處理的任務(wù)數(shù)) 由 7.37 提高到 15.35.
Time per request (每個用戶的平均處理時間) 由 135.686 降低到 65.126
3. 如何通過多進(jìn)程提高node.js 的性能
- Child Process 創(chuàng)建進(jìn)程
main.js
const Koa = require('Koa');
const koaRouter = require('koa-router');
const fork = require('child_process').fork;
const app = new Koa();
const router = new koaRouter();
app.use(router['routes']());
router.get('/', function(ctx, next) {
var worker = fork('./work_fibo.js');
worker.on('message', function(m) {
if ('object' === typeof m && m.type === 'fibo') {
worker.kill();
ctx.body = m.result.toString();
}
});
worker.send({type: "fibo", num: 35}, (err) => {
console.log(`${err}`);
});
console.log(`${worker.pid}`);
});
if (!module.parent) {
app.listen(8080);
console.log(`Server was start.`);
}
work_fibo.js
var fibo = function fibo(n) {
return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
}
process.on('message', function(m) {
if (typeof m === 'object' && m.type === 'fibo') {
var num = fibo(m.num);
process.send({type: 'fibo', result: num});
}
});
process.on('SIGHUP', function() {
process.exist();
});
通過ab 壓力測試命令:
ab -c 20 -n 100 http://localhost:8080/
Server Software:
Server Hostname: localhost
Server Port: 8080
Document Path: /
Document Length: 9 bytes
Concurrency Level: 20
Time taken for tests: 3.619 seconds
Complete requests: 100
Failed requests: 0
Non-2xx responses: 100
Total transferred: 15100 bytes
HTML transferred: 900 bytes
Requests per second: 27.63 [#/sec] (mean)
Time per request: 723.764 [ms] (mean)
Time per request: 36.188 [ms] (mean, across all concurrent requests)
Transfer rate: 4.07 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 4.5 0 43
Processing: 21 611 270.7 650 1134
Waiting: 18 610 270.7 649 1132
Total: 22 612 270.2 652 1134
Percentage of the requests served within a certain time (ms)
50% 652
66% 744
75% 794
80% 835
90% 958
95% 1054
98% 1122
99% 1134
100% 1134 (longest request)
對比兩次的測試結(jié)果:
優(yōu)化后泛鸟,
Requests per second (每秒處理的任務(wù)數(shù)) 由 7.37 提高到 15.35 最后通過進(jìn)程優(yōu)化后達(dá)到 27.63
Time per request (每個用戶的平均處理時間) 由 135.686 降低到 65.126 最后通過進(jìn)程優(yōu)化后達(dá)到 36.188