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