前言
我們都知道nodejs最大的特點就是單進(jìn)程、無阻塞運行,并且是異步事件驅(qū)動的。Nodejs的這些特性能夠很好的解決一些問題,例如在服務(wù)器開發(fā)中,并發(fā)的請求處理是個大問題,阻塞式的函數(shù)會導(dǎo)致資源浪費和時間延遲。通過事件注冊、異步函數(shù),開發(fā)人員可以提高資源的利用率,性能也會改善。既然Node.js采用單進(jìn)程、單線程模式,那么在如今多核硬件流行的環(huán)境中,單核性能出色的Nodejs如何利用多核CPU呢?創(chuàng)始人Ryan Dahl建議,運行多個Nodejs進(jìn)程,利用某些通信機制來協(xié)調(diào)各項任務(wù)。目前,已經(jīng)有不少第三方的Node.js多進(jìn)程支持模塊發(fā)布,而NodeJS 0.6.x 以上的版本提供了一個cluster模塊 ,允許創(chuàng)建“共享同一個socket”的一組進(jìn)程,用來分擔(dān)負(fù)載壓力。本篇文章就基于該cluster模塊來講述Node.js在多核CPU下的編程。
Cluster用法介紹
首先貼出一段該模板示例應(yīng)用代碼,接下來進(jìn)行分析,代碼如下
'use strict';
var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
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 {
process.env.NODE_ENV = 'production';
require('./server.js');
}
負(fù)載均衡問題
一個請求過來,是給worker進(jìn)程A處理,還是給worker進(jìn)程B處理呢?怎么保證大家均等的干活呢?這就是負(fù)載均衡的問題。
當(dāng)前有兩種可選的方法來做負(fù)載均衡。
早期的cluster是各個worker進(jìn)程自己去監(jiān)聽socket端口,由操作系統(tǒng)去喚醒worker進(jìn)程,大家可能很容易認(rèn)為操作系統(tǒng)會隨機的選擇worker進(jìn)程,于是就實現(xiàn)了服務(wù)的負(fù)載均衡。但實際上,像Linux操作系統(tǒng)總是喚醒某幾個進(jìn)程,因為對于系統(tǒng)來說,上下文切換時很昂貴的操作,喚醒最近被喚醒的進(jìn)程是比較好的選擇。早期的這種方式負(fù)載是很不均衡的。
從0.11.2版本開始,cluster開始增加了round-robin模式做負(fù)載均衡:master進(jìn)程負(fù)責(zé)監(jiān)聽,收到請求后轉(zhuǎn)發(fā)給worker進(jìn)程,多個worker進(jìn)程輪流干活。round-robin是當(dāng)前cluster的默認(rèn)負(fù)載均衡處理模式(除了windows平臺),如果要回到之前的模式,有兩種方式
(1)可以在cluster加載之后未調(diào)用其他cluster函數(shù)之前執(zhí)行:cluster.schedulingPolicy = cluster.SCHED_NODE;來設(shè)定。
(2)設(shè)置環(huán)境變量NODE_CLUSTER_SCHED_POLICY = "none"
進(jìn)程監(jiān)控
master進(jìn)程不會自動管理worker進(jìn)程的生死,如果worker被外界殺掉了,不會自動重啟,只會給master進(jìn)程發(fā)送‘exit’消息,開發(fā)者需要自己做好管理。
數(shù)據(jù)共享問題
各個worker進(jìn)程之間是獨立的,為了讓多個worker進(jìn)程共享數(shù)據(jù)(譬如用戶session),一般的做法是在Nodejs之外搭建一個數(shù)據(jù)庫,多個worker進(jìn)程通過數(shù)據(jù)庫做數(shù)據(jù)共享。